-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(cli): resolve proper versions with
install expo@canary --fix
(#…
…25702) # Why This is a follow-up of #25600 # How This PR addresses a couple of things: - `expo install <package> --fix` should only fix that package. But, `expo` affects all other packages, and should be handled properly when executing `expo install expo@canary --fix`. - Some package managers might use `"canary"` (dist tag) when installing through `expo install expo@canary`, meaning the canary detection from #25600 was not good enough. - Move the canary detection into `getCombinedKnownVersionsAsync` to include this in `expo install --fix` _**and**_ `expo install <package>`. # Test Plan - `$ bun create expo ./test-canary --template blank` - `$ bun expo install expo@canary --fix` - _should result in: `expo@canary` (or exact version), `expo-status-bar@0.0.x-canary-...`_ - `$ bun expo install expo-dev-client` - _should result in: `expo-dev-client@0.0.x-canary-...`_ - `$ bun expo install --check` -> _should show no errors_ There were edge cases, because this is a new concept and I can't really test this properly (it invokes the canary CLI, not CLI from source). Because of that, this is now not allowed: - `$ bun expo install expo@canary expo-dev-client --fix` The command above not only changes `expo@canary,` but it also invokes `expo install expo-dev-client --fix,` which throws because it's not yet installed. To avoid some confusion, this combination is aborted early without installing anything. # Checklist <!-- Please check the appropriate items below if they apply to your diff. This is required for changes to Expo modules. --> - [ ] Documentation is up to date to reflect these changes (eg: https://docs.expo.dev and README.md). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin).
- Loading branch information
Showing
8 changed files
with
321 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
packages/@expo/cli/src/start/doctor/dependencies/__tests__/resolvePackages.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import { vol } from 'memfs'; | ||
import resolveFrom from 'resolve-from'; | ||
|
||
import { | ||
resolvePackageVersionAsync, | ||
resolveAllPackageVersionsAsync, | ||
hasExpoCanaryAsync, | ||
} from '../resolvePackages'; | ||
|
||
afterEach(() => { | ||
vol.reset(); | ||
}); | ||
|
||
const projectRoot = '/fake/project'; | ||
|
||
describe(resolvePackageVersionAsync, () => { | ||
it('resolves installed package', async () => { | ||
vol.fromJSON( | ||
{ [`node_modules/expo/package.json`]: JSON.stringify({ version: '1.0.0' }) }, | ||
projectRoot | ||
); | ||
|
||
await expect(resolvePackageVersionAsync(projectRoot, 'expo')).resolves.toBe('1.0.0'); | ||
}); | ||
|
||
it('resolves installed package using `exports` without `package.json`', async () => { | ||
// Mock the Node error when not exporting `package.json` from `exports`. | ||
jest.mocked(resolveFrom).mockImplementationOnce(() => { | ||
const error: any = new Error( | ||
`Package subpath './package.json' is not defined by "exports" in ${projectRoot}/node_modules/expo/package.json` | ||
); | ||
error.code = 'ERR_PACKAGE_PATH_NOT_EXPORTED'; | ||
throw error; | ||
}); | ||
|
||
vol.fromJSON( | ||
{ | ||
[`node_modules/expo/package.json`]: JSON.stringify({ | ||
version: '2.0.0', | ||
exports: { | ||
'.': { | ||
require: './index.js', | ||
}, | ||
}, | ||
}), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(resolvePackageVersionAsync(projectRoot, 'expo')).resolves.toBe('2.0.0'); | ||
}); | ||
|
||
it('throws when package is not installed', async () => { | ||
vol.fromJSON({}, projectRoot); | ||
|
||
await expect(resolvePackageVersionAsync(projectRoot, 'expo')).rejects.toThrowError( | ||
`"expo" is added as a dependency in your project's package.json but it doesn't seem to be installed` | ||
); | ||
}); | ||
}); | ||
|
||
describe(resolveAllPackageVersionsAsync, () => { | ||
it('resolves installed packages', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`node_modules/expo/package.json`]: JSON.stringify({ version: '1.0.0' }), | ||
[`node_modules/react/package.json`]: JSON.stringify({ version: '2.0.0' }), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect( | ||
resolveAllPackageVersionsAsync(projectRoot, ['expo', 'react']) | ||
).resolves.toMatchObject({ | ||
expo: '1.0.0', | ||
react: '2.0.0', | ||
}); | ||
}); | ||
|
||
it('throws when package is not installed', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`node_modules/expo/package.json`]: JSON.stringify({ version: '1.0.0' }), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(resolveAllPackageVersionsAsync(projectRoot, ['expo', 'react'])).rejects.toThrow( | ||
`"react" is added as a dependency in your project's package.json but it doesn't seem to be installed` | ||
); | ||
}); | ||
}); | ||
|
||
describe(hasExpoCanaryAsync, () => { | ||
it('returns false for stable version from installed package', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`node_modules/expo/package.json`]: JSON.stringify({ version: '1.0.0' }), | ||
// This is not a common use-case, but tests the priority of strategies | ||
[`package.json`]: JSON.stringify({ | ||
version: '1.0.0', | ||
dependencies: { | ||
expo: 'canary', | ||
}, | ||
}), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(hasExpoCanaryAsync(projectRoot)).resolves.toBe(false); | ||
}); | ||
|
||
it('returns true for canary version from installed package', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`node_modules/expo/package.json`]: JSON.stringify({ | ||
version: '50.0.0-canary-20231130-c8a9bf9', | ||
}), | ||
// This is not a common use-case, but tests the priority of strategies | ||
[`package.json`]: JSON.stringify({ | ||
version: '1.0.0', | ||
dependencies: { | ||
expo: '1.0.0', | ||
}, | ||
}), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(hasExpoCanaryAsync(projectRoot)).resolves.toBe(true); | ||
}); | ||
|
||
it('returns false for stable version from package.json', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`package.json`]: JSON.stringify({ | ||
version: '1.0.0', | ||
dependencies: { | ||
expo: '1.0.0', | ||
}, | ||
}), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(hasExpoCanaryAsync(projectRoot)).resolves.toBe(false); | ||
}); | ||
|
||
it('returns true for canary version from package.json', async () => { | ||
vol.fromJSON( | ||
{ | ||
[`package.json`]: JSON.stringify({ | ||
version: '1.0.0', | ||
dependencies: { | ||
expo: 'canary', | ||
}, | ||
}), | ||
}, | ||
projectRoot | ||
); | ||
|
||
await expect(hasExpoCanaryAsync(projectRoot)).resolves.toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.