Skip to content

Commit 6b3f3e7

Browse files
authored
Refactors tests to abstract implementation details (yarnpkg#6711)
## What's the problem this PR addresses? Some of our tests rely on implementation details which can make refactoring more difficult. ## How did you fix it? This diff attempts to remove checks for things that don't directly match the test description, by using standard APIs as much as possible. For example, if a test wants to read a file from a dependency, it should do so by calling `require.resolve` to find out the location of this file rather than by hardcoding it. ## Checklist <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed.
1 parent 477c963 commit 6b3f3e7

File tree

13 files changed

+231
-65
lines changed

13 files changed

+231
-65
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ package.tgz
3030

3131
# Those files are meant to be local-only
3232
/packages/*/bundles
33+
/packages/yarnpkg-pnp/sources/hook.raw.js
3334

3435
# Those folders are meant to contain the prepack build artifacts; we don't commit them
3536
/packages/*/lib/*

.yarn/versions/744c99cf.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declined:
2+
- "@yarnpkg/pnp"

packages/acceptance-tests/pkg-tests-core/sources/utils/makeTemporaryEnv.ts

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const mte = generatePkgDriver({
3737
[`HOME`]: nativeHomePath,
3838
[`USERPROFILE`]: nativeHomePath,
3939
[`PATH`]: `${nativePath}/bin${delimiter}${process.env.PATH}`,
40+
[`RUST_BACKTRACE`]: `1`,
4041
[`YARN_IS_TEST_ENV`]: `true`,
4142
[`YARN_GLOBAL_FOLDER`]: `${nativePath}/.yarn/global`,
4243
[`YARN_NPM_REGISTRY_SERVER`]: registryUrl,

packages/acceptance-tests/pkg-tests-core/sources/utils/tests.ts

+48
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export enum RequestType {
5151
Login = `login`,
5252
PackageInfo = `packageInfo`,
5353
PackageTarball = `packageTarball`,
54+
PackageVersion = `packageVersion`,
5455
Whoami = `whoami`,
5556
Repository = `repository`,
5657
Publish = `publish`,
@@ -66,6 +67,12 @@ export type Request = {
6667
type: RequestType.PackageInfo;
6768
scope?: string;
6869
localName: string;
70+
} | {
71+
registry?: string;
72+
type: RequestType.PackageVersion;
73+
scope?: string;
74+
localName: string;
75+
version: string;
6976
} | {
7077
registry?: string;
7178
type: RequestType.PackageTarball;
@@ -409,6 +416,37 @@ export const startPackageServer = ({type}: {type: keyof typeof packageServerUrls
409416
response.end(data);
410417
},
411418

419+
async [RequestType.PackageVersion](parsedRequest, request, response) {
420+
if (parsedRequest.type !== RequestType.PackageVersion)
421+
throw new Error(`Assertion failed: Invalid request type`);
422+
423+
const {scope, localName, version} = parsedRequest;
424+
const name = scope ? `${scope}/${localName}` : localName;
425+
426+
const packageEntry = await getPackageEntry(name);
427+
if (!packageEntry) {
428+
processError(response, 404, `Package not found: ${name}`);
429+
return;
430+
}
431+
432+
const packageVersionEntry = packageEntry.get(version);
433+
invariant(packageVersionEntry, `This can only exist`);
434+
435+
const data = JSON.stringify({
436+
[version as string]: Object.assign({}, packageVersionEntry!.packageJson, {
437+
dist: {
438+
shasum: await getPackageArchiveHash(name, version),
439+
tarball: (localName === `unconventional-tarball` || localName === `private-unconventional-tarball`)
440+
? (await getPackageHttpArchivePath(name, version)).replace(`/-/`, `/tralala/`)
441+
: await getPackageHttpArchivePath(name, version),
442+
},
443+
}),
444+
});
445+
446+
response.writeHead(200, {[`Content-Type`]: `application/json`});
447+
response.end(data);
448+
},
449+
412450
async [RequestType.PackageTarball](parsedRequest, request, response) {
413451
if (parsedRequest.type !== RequestType.PackageTarball)
414452
throw new Error(`Assertion failed: Invalid request type`);
@@ -628,6 +666,16 @@ export const startPackageServer = ({type}: {type: keyof typeof packageServerUrls
628666
scope,
629667
localName,
630668
};
669+
} else if ((match = url.match(/^\/(?:(@[^/]+)\/)?([^@/][^/]*)\/([0-9]+\.[0-9]+\.[0-9]+(?:-[^/]+)?)$/))) {
670+
const [, scope, localName, version] = match;
671+
672+
return {
673+
...registry,
674+
type: RequestType.PackageVersion,
675+
scope,
676+
localName,
677+
version,
678+
};
631679
} else if ((match = url.match(/^\/(?:(@[^/]+)\/)?([^@/][^/]*)\/(-|tralala)\/\2-(.*)\.tgz(\?.*)?$/))) {
632680
const [, scope, localName, split, version] = match;
633681

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import {ppath, xfs} from '@yarnpkg/fslib';
2+
3+
describe(`Features`, () => {
4+
describe(`Berry Lockfile`, () => {
5+
test(`it should correctly import the lockfile from a Berry install`, makeTemporaryEnv({
6+
dependencies: {[`no-deps`]: `^1.0.0`},
7+
}, async ({path, run, source}) => {
8+
await xfs.writeFilePromise(ppath.join(path, `yarn.lock`), [
9+
`# This file is generated by running "yarn install" inside your project.\n`,
10+
`# Manual changes might be lost - proceed with caution!\n`,
11+
`\n`,
12+
`__metadata:\n`,
13+
` version: 8\n`,
14+
` cacheKey: 0c0\n`,
15+
`\n`,
16+
`"no-deps@npm:^1.0.0":\n`,
17+
` version: 1.0.0\n`,
18+
` resolution: "no-deps@npm:1.0.0"\n`,
19+
` checksum: 0c0/af041f19ffad13c40b220f0319b95436c0e886ddb630988d78e35eb3b4e3d64131f1e7e9efa5818a7f3307718e322220bda7676fcc202f1841e587aa079b7205\n`,
20+
` languageName: node\n`,
21+
` linkType: hard\n`,
22+
].join(``));
23+
24+
await run(`install`);
25+
26+
await expect(source(`require('no-deps')`)).resolves.toMatchObject({
27+
name: `no-deps`,
28+
version: `1.0.0`,
29+
});
30+
}));
31+
});
32+
});

packages/acceptance-tests/pkg-tests-specs/sources/features/resolutions.test.js

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {xfs} from '@yarnpkg/fslib';
1+
import {ppath, xfs} from '@yarnpkg/fslib';
22

33
const {
44
fs: {writeFile, writeJson},
@@ -109,6 +109,56 @@ describe(`Features`, () => {
109109
),
110110
);
111111

112+
test(
113+
`it should support overriding a packages with another, but only if its parent package has a specific version`,
114+
makeTemporaryEnv(
115+
{
116+
dependencies: {
117+
[`one-fixed-dep`]: `1.0.0`,
118+
},
119+
resolutions: {
120+
[`[email protected]/no-deps`]: `1.0.1`,
121+
},
122+
},
123+
async ({path, run, source}) => {
124+
await run(`install`);
125+
126+
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
127+
name: `one-fixed-dep`,
128+
version: `1.0.0`,
129+
dependencies: {
130+
[`no-deps`]: {
131+
name: `no-deps`,
132+
version: `1.0.1`,
133+
},
134+
},
135+
});
136+
137+
await xfs.writeJsonPromise(ppath.join(path, `package.json`), {
138+
dependencies: {
139+
[`one-fixed-dep`]: `2.0.0`,
140+
},
141+
resolutions: {
142+
[`[email protected]/no-deps`]: `1.0.1`,
143+
},
144+
});
145+
146+
await run(`install`);
147+
148+
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
149+
name: `one-fixed-dep`,
150+
version: `2.0.0`,
151+
dependencies: {
152+
[`no-deps`]: {
153+
name: `no-deps`,
154+
version: `2.0.0`,
155+
},
156+
},
157+
});
158+
},
159+
),
160+
);
161+
112162
test(
113163
`it should support overriding packages with portals`,
114164
makeTemporaryEnv(
@@ -141,7 +191,7 @@ describe(`Features`, () => {
141191
);
142192

143193
test(
144-
`it should error when legacy glob syntax is used`,
194+
`it should warn when legacy glob syntax is used`,
145195
makeTemporaryEnv(
146196
{
147197
resolutions: {

packages/acceptance-tests/pkg-tests-specs/sources/lock.test.ts

+37-10
Original file line numberDiff line numberDiff line change
@@ -31,31 +31,58 @@ describe(`Lock tests`, () => {
3131
`it shouldn't loose track of the resolutions when upgrading the lockfile version`,
3232
makeTemporaryEnv(
3333
{
34-
dependencies: {[`no-deps`]: `patch:no-deps@^1.0.0#`},
34+
dependencies: {[`one-range-dep`]: `1.0.0`},
3535
},
3636
async ({path, run, source}) => {
3737
await setPackageWhitelist(new Map([[`no-deps`, new Set([`1.0.0`])]]), async () => {
3838
await run(`install`);
3939
});
4040

41-
const lockfilePath = ppath.join(path, Filename.lockfile);
42-
const lockfile = await xfs.readFilePromise(lockfilePath, `utf8`);
43-
const expectedLockfile = lockfile.replace(/(__metadata:[\t\r\n ]*version: )([0-9]+)/, ($0, $1, $2) => `${$1}${parseInt($2, 10) + 1}`);
44-
45-
// Sanity check to be sure that the test does something
46-
expect(expectedLockfile).not.toEqual(lockfile);
41+
await expect(source(`require('one-range-dep')`)).resolves.toMatchObject({
42+
name: `one-range-dep`,
43+
version: `1.0.0`,
44+
dependencies: {
45+
[`no-deps`]: {
46+
name: `no-deps`,
47+
version: `1.0.0`,
48+
},
49+
},
50+
});
4751

4852
await setPackageWhitelist(new Map([[`no-deps`, new Set([`1.0.0`, `1.1.0`])]]), async () => {
4953
await run(`install`, {
5054
lockfileVersionOverride: LOCKFILE_VERSION + 1,
5155
});
5256
});
5357

54-
await expect(xfs.readFilePromise(lockfilePath, `utf8`)).resolves.toEqual(expectedLockfile);
58+
await expect(source(`require('one-range-dep')`)).resolves.toMatchObject({
59+
name: `one-range-dep`,
60+
version: `1.0.0`,
61+
dependencies: {
62+
[`no-deps`]: {
63+
name: `no-deps`,
64+
version: `1.0.0`,
65+
},
66+
},
67+
});
5568

56-
await expect(source(`require('no-deps')`)).resolves.toMatchObject({
57-
name: `no-deps`,
69+
await xfs.rmPromise(ppath.join(path, Filename.lockfile));
70+
71+
await setPackageWhitelist(new Map([[`no-deps`, new Set([`1.0.0`, `1.1.0`])]]), async () => {
72+
await run(`install`, {
73+
lockfileVersionOverride: LOCKFILE_VERSION + 2,
74+
});
75+
});
76+
77+
await expect(source(`require('one-range-dep')`)).resolves.toMatchObject({
78+
name: `one-range-dep`,
5879
version: `1.0.0`,
80+
dependencies: {
81+
[`no-deps`]: {
82+
name: `no-deps`,
83+
version: `1.1.0`,
84+
},
85+
},
5986
});
6087
},
6188
),

packages/acceptance-tests/pkg-tests-specs/sources/pnp.test.js

+12-19
Original file line numberDiff line numberDiff line change
@@ -1631,20 +1631,18 @@ describe(`Plug'n'Play`, () => {
16311631
},
16321632
},
16331633
async ({path, run, source}) => {
1634+
await writeFile(`${path}/dep/index.js`, `module.exports = require('./package.json');`);
1635+
16341636
await writeJson(npath.toPortablePath(`${path}/dep/package.json`), {
16351637
name: `dep`,
16361638
version: `1.0.0`,
16371639
os: [`!${process.platform}`],
16381640
scripts: {
1639-
postinstall: `echo 'Shall not be run'`,
1641+
postinstall: `echo 'module.exports = 42;' > index.js`,
16401642
},
16411643
});
1642-
await writeFile(`${path}/dep/index.js`, `module.exports = require('./package.json');`);
1643-
1644-
const stdout = (await run(`install`)).stdout;
16451644

1646-
expect(stdout).not.toContain(`Shall not be run`);
1647-
expect(stdout).toMatch(new RegExp(`dep@file:./dep.*The ${process.platform}-${process.arch}(-[a-z]+)? architecture is incompatible with this package, build skipped.`));
1645+
await run(`install`);
16481646

16491647
await expect(source(`require('dep')`)).resolves.toMatchObject({
16501648
name: `dep`,
@@ -1956,22 +1954,17 @@ describe(`Plug'n'Play`, () => {
19561954
},
19571955
},
19581956
async ({path, run, source}) => {
1959-
await expect(run(`install`)).resolves.toMatchObject({
1960-
code: 0,
1961-
stdout: expect.stringContaining(`YN0007`),
1962-
});
1963-
1964-
await expect(run(`install`)).resolves.toMatchObject({
1965-
code: 0,
1966-
stdout: expect.not.stringContaining(`YN0007`),
1967-
});
1957+
await run(`install`);
19681958

19691959
await xfs.removePromise(ppath.join(path, `.yarn/unplugged`));
19701960

1971-
await expect(run(`install`)).resolves.toMatchObject({
1972-
code: 0,
1973-
stdout: expect.stringContaining(`YN0007`),
1974-
});
1961+
await run(`install`);
1962+
1963+
await expect(source(`require('no-deps-scripted/log')`)).resolves.toEqual([
1964+
`preinstall`,
1965+
`install`,
1966+
`postinstall`,
1967+
]);
19751968
},
19761969
),
19771970
);

packages/acceptance-tests/pkg-tests-specs/sources/pnpapi.test.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe(`Plug'n'Play API`, () => {
8484
await run(`install`);
8585

8686
await expect(
87-
source(`typeof require('pnpapi').getPackageInformation({name: null, reference: null}).packageLocation`),
87+
source(`typeof require('pnpapi').getPackageInformation(require('pnpapi').topLevel).packageLocation`),
8888
).resolves.toEqual(
8989
`string`,
9090
);
@@ -102,10 +102,10 @@ describe(`Plug'n'Play API`, () => {
102102
await run(`install`);
103103

104104
await expect(
105-
source(`[...require('pnpapi').getPackageInformation({name: null, reference: null}).packageDependencies]`),
105+
source(`[...require('pnpapi').getPackageInformation(require('pnpapi').topLevel).packageDependencies].sort((a, b) => a[0].localeCompare(b[0]))`),
106106
).resolves.toEqual([
107107
[`no-deps`, `npm:1.0.0`],
108-
[`root-workspace`, `workspace:.`],
108+
[`root-workspace`, expect.stringContaining(`workspace:`)],
109109
]);
110110
}),
111111
);
@@ -165,8 +165,9 @@ describe(`Plug'n'Play API`, () => {
165165

166166
await expect(
167167
source(`{
168+
const path = require('path');
168169
const pnp = require('pnpapi');
169-
const deps = pnp.getPackageInformation({name: 'foo', reference: 'workspace:packages/foo'}).packageDependencies;
170+
const deps = pnp.getPackageInformation(pnp.findPackageLocator(path.resolve('packages/foo/package.json'))).packageDependencies;
170171
return [...pnp.getPackageInformation(pnp.getLocator('bar', deps.get('bar'))).packagePeers];
171172
}`),
172173
).resolves.toEqual([
@@ -208,8 +209,9 @@ describe(`Plug'n'Play API`, () => {
208209

209210
await expect(
210211
source(`{
212+
const path = require('path');
211213
const pnp = require('pnpapi');
212-
return [...pnp.getPackageInformation({name: 'bar', reference: 'workspace:packages/bar'}).packagePeers || []];
214+
return [...pnp.getPackageInformation(pnp.findPackageLocator(path.resolve('packages/bar'))).packagePeers || []];
213215
}`),
214216
).resolves.toEqual([]);
215217
}),
@@ -338,7 +340,7 @@ describe(`Plug'n'Play API`, () => {
338340
await run(`install`);
339341

340342
const reference = await source(
341-
`require('pnpapi').getPackageInformation({name: null, reference: null}).packageDependencies.get('no-deps')`,
343+
`require('pnpapi').getPackageInformation(require('pnpapi').topLevel).packageDependencies.get('no-deps')`,
342344
);
343345

344346
await expect(
@@ -359,7 +361,7 @@ describe(`Plug'n'Play API`, () => {
359361
await run(`install`);
360362

361363
const reference = await source(
362-
`require('pnpapi').getPackageInformation({name: null, reference: null}).packageDependencies.get('self')`,
364+
`require('pnpapi').getPackageInformation(require('pnpapi').topLevel).packageDependencies.get('self')`,
363365
);
364366

365367
await expect(

0 commit comments

Comments
 (0)