Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: use native ESM #2621

Merged
merged 16 commits into from
Dec 12, 2022
Merged

test: use native ESM #2621

merged 16 commits into from
Dec 12, 2022

Conversation

gao-sun
Copy link
Member

@gao-sun gao-sun commented Dec 8, 2022

Summary

Use native ESM for testing to avoid CJS transpiling and config hacking and significantly boost the testing speed.

Did for cli and core - other packages will be in a separate PR.


Say goodbye to config hacking

forget transformIgnorePatterns and compatibility mocks - they are terrible

image

image


Code freeze on core/src/routes/session

It's going to be replaced by the new interaction API - so I skipped the code refactor and added code owners @simeng-li @wangsijie. Until you have a good reason, don't touch the code.

If you have to touch them (e.g. emergency bug fix). call it out in the eng Slack channel.


Remove useless jest.fn()

Don't use useless nested jest.fn()!

image

mockHasUser() is already a jest mock - but inside the module mock

image

this jest.fn() is useless and creates another layer of mocking i think.


No mock scope issue

You don't need to define a mock function in the outer scope - looks like a hoist-related issue (didn't deep dive). See the example section for details.


Ceveats

  • ES Modules are immutable. Thus you CANNOT use jest.mock() anymore. Instead, use mockEsm() and its relative utils. (check #src/test-utils/mock.ts for all helpers)
    • We use jest.unstable_mockModule() under the hood, actually it's okay - all ESM "mocking" libs I saw are using the same technique - create a new "revision" of the module. it's straight and simple. see [jest docs] (https://jestjs.io/docs/ecmascript-modules#module-mocking-in-esm)
    • didn't check the reason of "unstable" but seems it's because the flag node's experimental-vm-modules is marked as "experimental" since v12.16.0. don't see the issue if it's for testing only.
  • jest.spyOn(moduleName, method) will NOT work for modules, but still works for mutable objects.
  • Due the previous note, you cannot directly use the global jest directly in ESM. put const { jest } = import.meta; before any expression to make it feel as usual.
  • Unlike jest.mock() for CJS, which will be automatically hoisted; in ESM, due to the static module structure, every time you mock a module, it will NOT affect the modules already imported. So the order of import MATTERS.

Example

Code size

See how native ESM reduce the code size, in a connector test file:

mockEsmWithActual() (also mockEsm(), mockEsmDefault()) will return the mocked functions, so you can deconstruct them:

image

since you can mock them inline, so no more as jest.SomeMockType

image

and no need for importing again and renaming to mockFoo or fooPlaceholder:

image

image

Use dynamic import for what you want to test

Since the import order matters, to avoid "why the mock is not working" situation, import the module you want to test as late as you can (usually before the first describe()):

image


Testing

original

image

now

image

3x - 4x faster

@github-actions
Copy link

github-actions bot commented Dec 8, 2022

COMPARE TO master

Total Size Diff 📈 +3.39 KB

Diff by File
Name Diff
.github/CODEOWNERS 📈 +56 Bytes
.github/workflows/main.yml 📈 +126 Bytes
packages/cli/jest.config.js 📈 +280 Bytes
packages/cli/jest.config.ts 📈 +520 Bytes
packages/cli/jest.setup.ts 📈 +429 Bytes
packages/cli/package.json 📈 +133 Bytes
packages/cli/src/commands/database/alteration/index.test.ts 📈 +89 Bytes
packages/cli/src/commands/database/alteration/index.ts 📈 +1.72 KB
packages/cli/src/commands/database/alteration/utils.ts 📈 +1.88 KB
packages/cli/src/commands/database/alteration/version.ts 📈 +1 Bytes
packages/cli/src/queries/logto-config.test.ts 📈 +30 Bytes
packages/cli/src/utilities.ts 📈 +32 Bytes
packages/cli/tsconfig.test.json 📈 +22 Bytes
packages/console/package.json 📈 +1 Bytes
packages/core/jest.config.js 📈 +546 Bytes
packages/core/jest.config.ts 📈 +634 Bytes
packages/core/jest.setup.js 📈 +931 Bytes
packages/core/jest.setup.ts 📈 +777 Bytes
packages/core/package.json 📈 +170 Bytes
packages/core/src/mocks/connector.ts 📈 +31 Bytes
packages/core/src/app/init.test.ts 📈 +491 Bytes
packages/core/src/connectors/utilities/index.test.ts 📈 +4 Bytes
packages/core/src/database/insert-into.test.ts 📈 +30 Bytes
packages/core/src/database/update-where.test.ts 📈 +30 Bytes
packages/core/src/database/update-where.ts 0 Bytes
packages/core/src/i18n/detect-language.test.ts 📈 +27 Bytes
packages/core/src/lib/passcode.test.ts 📈 +630 Bytes
packages/core/src/lib/phrase.test.ts 📈 +25 Bytes
packages/core/src/lib/sign-in-experience/index.test.ts 📈 +302 Bytes
packages/core/src/lib/sign-in-experience/sign-up.test.ts 📈 +61 Bytes
packages/core/src/lib/user.test.ts 📈 +73 Bytes
packages/core/src/middleware/koa-auth.test.ts 📈 +161 Bytes
packages/core/src/middleware/koa-connector-error-handler.test.ts 📈 +31 Bytes
packages/core/src/middleware/koa-error-handler.test.ts 📈 +57 Bytes
packages/core/src/middleware/koa-guard.test.ts 📈 +106 Bytes
packages/core/src/middleware/koa-i18next.test.ts 📈 +64 Bytes
packages/core/src/middleware/koa-log-session.test.ts 📈 +44 Bytes
packages/core/src/middleware/koa-log.test.ts 📈 +4 Bytes
packages/core/src/middleware/koa-oidc-error-handler.test.ts 📈 +31 Bytes
packages/core/src/middleware/koa-pagination.test.ts 📈 +58 Bytes
packages/core/src/middleware/koa-root-proxy.test.ts 📈 +31 Bytes
packages/core/src/middleware/koa-slonik-error-handler.test.ts 📈 +31 Bytes
packages/core/src/middleware/koa-spa-proxy.test.ts 📈 +95 Bytes
packages/core/src/middleware/koa-spa-session-guard.test.ts 📈 +91 Bytes
packages/core/src/middleware/koa-welcome-proxy.test.ts 📈 +53 Bytes
packages/core/src/oidc/adapter.test.ts 📈 +104 Bytes
packages/core/src/queries/application.test.ts 📈 +30 Bytes
packages/core/src/queries/connector.test.ts 📈 +30 Bytes
packages/core/src/queries/oidc-model-instance.test.ts 📈 +67 Bytes
packages/core/src/queries/passcode.test.ts 📈 +30 Bytes
packages/core/src/queries/resource.test.ts 📈 +30 Bytes
packages/core/src/queries/roles.test.ts 📈 +30 Bytes
packages/core/src/queries/setting.test.ts 📈 +30 Bytes
packages/core/src/queries/sign-in-experience.test.ts 📈 +30 Bytes
packages/core/src/queries/user.test.ts 📈 +30 Bytes
packages/core/src/routes/admin-user.test.ts 📈 +115 Bytes
packages/core/src/routes/application.test.ts 📈 +6 Bytes
packages/core/src/routes/authn.test.ts 📈 +103 Bytes
packages/core/src/routes/connector.test.ts 📈 +589 Bytes
packages/core/src/routes/connector.update.test.ts 📈 +208 Bytes
packages/core/src/routes/custom-phrase.test.ts 📈 +427 Bytes
packages/core/src/routes/dashboard.test.ts 📈 +520 Bytes
packages/core/src/routes/interaction/actions/submit-interaction.test.ts 📈 +104 Bytes
packages/core/src/routes/interaction/index.test.ts 📈 +246 Bytes
packages/core/src/routes/interaction/middleware/koa-interaction-body-guard.test.ts 📈 +53 Bytes
packages/core/src/routes/interaction/middleware/koa-session-sign-inexperience-guard.test.ts 📈 +37 Bytes
packages/core/src/routes/interaction/utils/find-user-by-identifier.test.ts 📈 +10 Bytes
packages/core/src/routes/interaction/utils/passcode-validation.test.ts 📈 +36 Bytes
packages/core/src/routes/interaction/utils/social-verification.test.ts 📈 +54 Bytes
packages/core/src/routes/interaction/verifications/identifier-payload-verification.test.ts 📈 +350 Bytes
packages/core/src/routes/interaction/verifications/mandatory-user-profile-validation.test.ts 📈 +118 Bytes
packages/core/src/routes/interaction/verifications/profile-verification-forgot-password.test.ts 📈 +69 Bytes
packages/core/src/routes/interaction/verifications/profile-verification-profile-exist.test.ts 📈 +97 Bytes
packages/core/src/routes/interaction/verifications/profile-verification-profile-registered.test.ts 📈 +92 Bytes
packages/core/src/routes/interaction/verifications/profile-verification-protected-identifier.test.ts 📈 +9 Bytes
packages/core/src/routes/interaction/verifications/user-identity-verification.test.ts 📈 +93 Bytes
packages/core/src/routes/log.test.ts 📈 +234 Bytes
packages/core/src/routes/phrase.content-language.test.ts 📈 +166 Bytes
packages/core/src/routes/phrase.test.ts 📈 +194 Bytes
packages/core/src/routes/profile.test.ts 📈 +901 Bytes
packages/core/src/routes/profile.ts 📈 +3 Bytes
packages/core/src/routes/resource.test.ts 📈 +35 Bytes
packages/core/src/routes/role.test.ts 📈 +109 Bytes
packages/core/src/routes/session/utils.test.ts 📈 +26 Bytes
packages/core/src/routes/setting.test.ts 📈 +47 Bytes
packages/core/src/routes/sign-in-experience.branding.guard.test.ts 📈 +87 Bytes
packages/core/src/routes/sign-in-experience.color.guard.test.ts 📈 +87 Bytes
packages/core/src/routes/sign-in-experience.guard.test.ts 📈 +113 Bytes
packages/core/src/routes/sign-in-experience.test.ts 📈 +301 Bytes
packages/core/src/routes/swagger.test.ts 📈 +55 Bytes
packages/core/src/routes/well-known.test.ts 📈 +35 Bytes
packages/core/src/test-utils/jest-koa-mocks/LICENSE 📈 +1.05 KB
packages/core/src/test-utils/jest-koa-mocks/README.md 📈 +193 Bytes
packages/core/src/test-utils/jest-koa-mocks/create-mock-context.ts 📈 +3.29 KB
packages/core/src/test-utils/jest-koa-mocks/create-mock-cookies.ts 📈 +951 Bytes
packages/core/src/test-utils/oidc-provider.ts 📈 +758 Bytes
packages/core/src/utils/oidc-provider-event-listener.test.ts 📈 +270 Bytes
packages/core/src/utils/test-utils.ts 📈 +56 Bytes
packages/shared/package.json 📈 +129 Bytes
packages/shared/src/esm/index.ts 📈 +91 Bytes
packages/shared/src/esm/mock-esm.ts 📈 +2.22 KB
packages/shared/src/esm/module-proxy.ts 📈 +350 Bytes
packages/shared/src/include.d/import-meta.d.ts 📈 +260 Bytes
packages/shared/src/utils/index.ts 📈 +60 Bytes
packages/shared/src/utils/module-proxy.ts 📈 +320 Bytes
pnpm-lock.yaml 📈 +778 Bytes

@uffizzi-cloud
Copy link

uffizzi-cloud bot commented Dec 8, 2022

This branch has been deployed using Uffizzi.

Preview URL:
https://pr-2621-deployment-8687-logto.app.uffizzi.com

View deployment details here:
https://https://app.uffizzi.com/projects/4064/deployments

This is an automated comment. To turn off commenting, visit uffizzi.com.

@github-actions github-actions bot added size/xl and removed size/m labels Dec 10, 2022
@gao-sun gao-sun force-pushed the gao-test-native-esm branch from 9837e02 to 5644948 Compare December 10, 2022 11:29
@gao-sun gao-sun force-pushed the gao-test-native-esm branch from 5644948 to c95b2ff Compare December 10, 2022 11:33
@gao-sun gao-sun force-pushed the gao-test-native-esm branch 2 times, most recently from 930b648 to 6f59c0a Compare December 10, 2022 13:19
@gao-sun gao-sun requested review from a team, charIeszhao and simeng-li and removed request for a team December 10, 2022 14:22
@gao-sun gao-sun changed the title test(cli): use native ESM test: use native ESM Dec 11, 2022
@gao-sun gao-sun force-pushed the gao-test-native-esm branch from 6f59c0a to 06d653a Compare December 11, 2022 05:22
@gao-sun gao-sun marked this pull request as ready for review December 11, 2022 08:19
@gao-sun gao-sun merged commit 25f0a2e into master Dec 12, 2022
@gao-sun gao-sun deleted the gao-test-native-esm branch December 12, 2022 05:43
Comment on lines +7 to +17
// See https://github.com/sindresorhus/callsites
/* eslint-disable @silverhand/fp/no-mutation */
const callSites = (): NodeJS.CallSite[] => {
const _prepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const stack = new Error().stack?.slice(1); // eslint-disable-line unicorn/error-message
Error.prepareStackTrace = _prepareStackTrace;

// @ts-expect-error ignore the error since it has been replaced with the original stack array
return stack ?? [];
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also copy the callsites license to our code base, as they are using MIT

@gao-sun gao-sun mentioned this pull request Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

4 participants