Skip to content

Commit d0fd727

Browse files
nikosdouvlisanagstefdesiprisg
authored
test(clerk-js): Introduce clerk-js testing infrastructure
* test(clerk-js): Change Jest config to work with imports instead of globals * test(clerk-js): Enable jest globals again for now * test(clerk-js): Add initial wip test for SignInStart component * test(clerk-js): WIP still but some progress is done on providers * test(clerk-js): WIP trying some stuff * test(clerk-js): WIP it renders SignInStart * test(clerk-js): WIP implement some of the structure of the PoC * test(clerk-js): WIP write some tests for SignInStart login methods * test(clerk-js): WIP add more tests * test(clerk-js): WIP Enable again module mappers * test(clerk-js): WIP Add one more test on SignInStart * test(clerk-js): WIP rename function which creates contexts * chore(repo): Use latest `jest` and remove `@types/jest` * chore(repo): Tweak jest config to work with latest * chore(repo): Update broken snapshots * chore(repo): Simplify internal api by reexporting MockClerkProvider as wrapper * test(clerk-js): WIP test social OAuth in SignInStart in a more generic way * test(clerk-js): WIP test all social OAuth login strategies * test(clerk-js): Minor refactors on fixture building * chore(clerk-js): Remove @types/jest * chore(clerk-js): Introduce new testUtils * chore(clerk-js): Add the ability to bind createFixture to a specific component * chore(clerk-js): Use new testUtils in SignInStart and SignUpStart * test(clerk-js): Add some tests for SignInFactorOne * chore(clerk-js): Rename mocks to fixtures * test(clerk-js): Add placeholders for all the tests we need for SignInFactorOne * chore(clerk-js): Revamp environment mocking * test(clerk-js): Add placeholders for all the tests we need for SignInFactorTwo * test(clerk-js): Add placeholders for all the tests we need for SignInAccountSwitcher * chore(clerk-js): Rename `user` to `userEvent` in testUtils * chore(clerk-js): Revamp clerk mocking * chore(clerk-js): Introduce client.signIn fixture helpers * test(clerk-js): Add withMagicLink fixture helper * test(clerk-js): Fix a navigation test in SignInStart * test(clerk-js): Add mock for Phone Code Factor One * test(clerk-js): Fix main SignInFactorOne tests * test(clerk-js): Fix all breaking SignIn tests * test(clerk-js): Add first AlternativeMethods tests * chore(clerk-js): Revamp route mock builders * chore(clerk-js): Replace _createFixture with bindCreateFixtures * chore(clerk-js): Make createFixtures support multiple config functions * test(clerk-js): Complete AlternativeMethod tests for SignInFactorOne * test(clerk-js): Add tests for SignInFactorOne * test(clerk-js): Add more tests for SignInFactorOne component * chore(clerk-js): Move utils.test.ts into __tests__ directory * test(clerk-js): Sign up options tests for SignUpStart * test(clerk-js): Finish SignUpStart testing * chore(clerk-js): Introduce client.signUp fixture helpers * test(clerk-js): Tests for SignUpVerifyEmail route * test(clerk-js): Tests for SignUpVerifyPhone route * chore(clerk-react): Update jest config * chore(clerk-js): Temporarily skip broken tests * chore(clerk-js): Fix eslint and typescript warnings for tests * chore(clerk-js): Add environment to fixtures and add signUp id to sign up helper * test(clerk-js): Tests for SignUpContinue component * test(clerk-js): Tests for SignUpEmailLinkFlowComplete * chore(clerk-js): Move all SignUp tests in the __tests__ directory * test(clerk-js): Tests for SignInFactorTwo submitting * test(clerk-js): Add status to attemptFirstFactor mock * test(clerk-js): Add tests for resend button and FAPI errors on SignInFactorOne * test(clerk-js): Add tests on SignInFactorTwo for phone code, backup codes and authenticator app * test(clerk-js): Skip the last test on SignInFactorOne * test(clerk-js): Remove delay from UserEvent setup to make it compatible with jest fake timers * test(clerk-js): Fix test using fake timers and UserEvent * chore(clerk-js): Change test email * test(clerk-js): Create sign in active sessions helper * test(clerk-js): Add tests for SignInAccountSwitcher * test(clerk-js): Add AlternativeMethod/GetHelp tests for SignInFactorTwo * test(clerk-js): Refactor typing test in SignInFactorTwo * chore(clerk-js): Organize all tests in __tests__ directories * test(clerk-js): Add test for SignInAccountSwitcher sign out * test(clerk-js): Add createFixtures.config * test(clerk-js): Enable single session mode by default * test(clerk-js): Revamp user fixtures * chore(repo): Update package-lock.json Co-authored-by: anagstef <anagstef@gmail.com> Co-authored-by: George Desipris <george.desipris.56@gmail.com>
1 parent 2a8cf34 commit d0fd727

File tree

68 files changed

+9814
-1868
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+9814
-1868
lines changed

package-lock.json

+7,266-1,722
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/backend-core/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"tslib": "^2.3.1"
2525
},
2626
"devDependencies": {
27-
"@types/jest": "^27.4.0",
2827
"jest": "^27.4.7",
2928
"nock": "^13.2.1",
3029
"ts-jest": "^27.1.3",

packages/clerk-js/jest.config.js

+39-49
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,45 @@
1-
module.exports = {
2-
// The root of your source code, typically /src
3-
// `<rootDir>` is a token Jest substitutes
4-
roots: ['<rootDir>/src'],
5-
testEnvironment: 'jsdom',
6-
7-
// Global settings
8-
globals: {
9-
'ts-jest': {
10-
tsconfig: 'tsconfig.test.json',
11-
},
12-
},
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
const config = {
3+
displayName: 'clerk-js',
4+
injectGlobals: true,
135

14-
// Coverage
15-
collectCoverageFrom: [
16-
'**/*.{js,jsx,ts,tsx}',
17-
'!**/*.d.ts',
18-
'!**/index.ts',
19-
'!**/index.browser.ts',
20-
'!**/index.headless.ts',
21-
'!**/index.headless.browser.ts',
22-
'!**/coverage/**',
23-
'!**/dist/**',
24-
'!**/node_modules/**',
25-
],
6+
testEnvironment: 'jsdom',
7+
roots: ['<rootDir>/src'],
8+
setupFiles: ['./setupJest.ts'],
9+
setupFilesAfterEnv: ['./setupJestAfterEnv.ts'],
10+
testRegex: ['/ui/.*/__tests__/.*.test.[jt]sx?$', '/(core|utils)/.*.test.[jt]sx?$'],
11+
testPathIgnorePatterns: ['/node_modules/'],
2612

27-
// Jest transformations -- this adds support for TypeScript
28-
// using ts-jest
13+
collectCoverage: false,
14+
coverageProvider: 'v8',
15+
coverageDirectory: 'coverage',
16+
coveragePathIgnorePatterns: ['/node_modules/'],
17+
// collectCoverageFrom: [
18+
// '**/*.{js,jsx,ts,tsx}',
19+
// '!**/*.d.ts',
20+
// '!**/index.ts',
21+
// '!**/index.browser.ts',
22+
// '!**/index.headless.ts',
23+
// '!**/index.headless.browser.ts',
24+
// '!**/coverage/**',
25+
// '!**/dist/**',
26+
// '!**/node_modules/**',
27+
// ],
28+
29+
moduleDirectories: ['node_modules', '<rootDir>/src'],
2930
transform: {
30-
'^.+\\.tsx?$': 'ts-jest',
31+
'^.+\\.m?tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json', diagnostics: false }],
32+
// '^.+\\.m?tsx?$': ['@swc/jest'],
33+
'^.+\\.svg$': '<rootDir>/svgTransform.js',
3134
},
3235

33-
// For mocking fetch
34-
automock: false,
35-
setupFiles: ['./setupJest.js'],
36-
setupFilesAfterEnv: ['<rootDir>../../setupJest.afterEnv.js'],
37-
38-
// Test spec file resolution pattern
39-
// Matches parent folder `__tests__` and filename
40-
// should contain `test` or `spec`.
41-
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
42-
43-
// Module file extensions for importings
44-
transformIgnorePatterns: ['^.+\\.module\\.(css|sass|scss)$'],
45-
46-
moduleNameMapper: {
47-
'^ui/(.*)': '<rootDir>/src/ui/$1',
48-
'^core/(.*)': '<rootDir>/src/core/$1',
49-
'^utils/(.*)$': '<rootDir>/src/utils/$1',
50-
'^utils': '<rootDir>/src/utils',
51-
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
52-
},
53-
54-
testPathIgnorePatterns: ['/node_modules/'],
36+
// moduleNameMapper: {
37+
// '^ui/(.*)': '<rootDir>/src/ui/$1',
38+
// '^core/(.*)': '<rootDir>/src/core/$1',
39+
// '^utils/(.*)$': '<rootDir>/src/utils/$1',
40+
// '^utils': '<rootDir>/src/utils',
41+
// '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
42+
// },
5543
};
44+
45+
module.exports = config;

packages/clerk-js/package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"postpublish": "node ./scripts/purge-cache.mjs",
3636
"start": "echo \"Noop\"",
3737
"test": "jest",
38-
"test:coverage": "jest --collectCoverage"
38+
"test:coverage": "jest --collectCoverage && open coverage/lcov-report/index.html"
3939
},
4040
"dependencies": {
4141
"@clerk/shared": "^0.5.4",
@@ -64,14 +64,14 @@
6464
"@babel/preset-env": "^7.12.1",
6565
"@babel/preset-react": "^7.12.5",
6666
"@babel/preset-typescript": "^7.12.1",
67+
"@emotion/jest": "^11.10.5",
6768
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
6869
"@svgr/webpack": "^6.2.1",
6970
"@testing-library/dom": "^8.19.0",
7071
"@testing-library/jest-dom": "^5.16.5",
7172
"@testing-library/react": "^13.4.0",
7273
"@testing-library/user-event": "^14.4.3",
7374
"@types/classnames": "^2",
74-
"@types/jest": "^27.4.0",
7575
"@types/jsonwebtoken": "^8",
7676
"@types/qs": "^6.9.3",
7777
"@types/react": "*",
@@ -86,7 +86,8 @@
8686
"css-loader": "^6.7.1",
8787
"fork-ts-checker-webpack-plugin": "^7.2.11",
8888
"identity-obj-proxy": "^3.0.0",
89-
"jest": "^27.4.7",
89+
"jest": "^29.3.0",
90+
"jest-environment-jsdom": "^29.3.0",
9091
"jsonwebtoken": "^8.5.1",
9192
"node-fetch": "^2.6.0",
9293
"postcss": "^8.4.13",
@@ -100,7 +101,7 @@
100101
"sass-loader": "^12.6.0",
101102
"semver": "^7.3.5",
102103
"style-loader": "^2.0.0",
103-
"ts-jest": "^27.1.3",
104+
"ts-jest": "^29.0.3",
104105
"ts-loader": "^9.3.0",
105106
"type-fest": "^0.20.2",
106107
"typescript": "*",

packages/clerk-js/setupJest.js

-7
This file was deleted.

packages/clerk-js/setupJest.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { jest } from '@jest/globals';
2+
3+
window.ResizeObserver =
4+
window.ResizeObserver ||
5+
jest.fn().mockImplementation(() => ({
6+
disconnect: jest.fn(),
7+
observe: jest.fn(),
8+
unobserve: jest.fn(),
9+
}));
10+
11+
Object.defineProperty(window, 'matchMedia', {
12+
writable: true,
13+
value: jest.fn().mockImplementation(query => ({
14+
matches: false,
15+
media: query,
16+
onchange: null,
17+
addListener: jest.fn(), // deprecated
18+
removeListener: jest.fn(), // deprecated
19+
addEventListener: jest.fn(),
20+
removeEventListener: jest.fn(),
21+
dispatchEvent: jest.fn(),
22+
})),
23+
});
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import '@testing-library/jest-dom';
2+
// import { afterEach } from '@jest/globals';
3+
// import { cleanup } from '@testing-library/react';
4+
//
5+
// /**
6+
// * RTL cannot automatically run cleanup after every test because
7+
// * we're not injecting jest helpers globally.
8+
// * This file is picked up by jest.config.ts and mounts cleanup as RTL would
9+
// * https://github.com/testing-library/testing-library-docs/pull/645
10+
// */
11+
// afterEach(cleanup);

packages/clerk-js/src/core/resources/__snapshots__/Organization.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Organization {
1515
"name": "test_name",
1616
"pathRoot": "/organizations",
1717
"pendingInvitationsCount": 10,
18-
"publicMetadata": Object {
18+
"publicMetadata": {
1919
"public": "metadata",
2020
},
2121
"removeMember": [Function],

packages/clerk-js/src/core/resources/__snapshots__/OrganizationInvitation.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ OrganizationInvitation {
77
"id": "test_id",
88
"organizationId": "test_organization_id",
99
"pathRoot": "",
10-
"publicMetadata": Object {
10+
"publicMetadata": {
1111
"public": "metadata",
1212
},
1313
"revoke": [Function],

packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembership.test.ts.snap

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ OrganizationMembership {
1919
"name": "test_name",
2020
"pathRoot": "/organizations",
2121
"pendingInvitationsCount": 10,
22-
"publicMetadata": Object {
22+
"publicMetadata": {
2323
"public": "metadata",
2424
},
2525
"removeMember": [Function],
@@ -30,10 +30,10 @@ OrganizationMembership {
3030
"updatedAt": 1970-01-01T00:01:07.890Z,
3131
},
3232
"pathRoot": "",
33-
"publicMetadata": Object {
33+
"publicMetadata": {
3434
"foo": "bar",
3535
},
36-
"publicUserData": Object {
36+
"publicUserData": {
3737
"firstName": "test_first_name",
3838
"identifier": "test@identifier.gr",
3939
"lastName": "test_last_name",

packages/clerk-js/src/testUtils.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { render as _render, RenderOptions } from '@testing-library/react';
2+
import UserEvent from '@testing-library/user-event';
3+
import React from 'react';
4+
5+
const render = (ui: React.ReactElement, options?: RenderOptions) => {
6+
const userEvent = UserEvent.setup({ delay: null });
7+
return { ..._render(ui, { ...options }), userEvent };
8+
};
9+
10+
export * from './ui/utils/test/createFixtures';
11+
export * from '@testing-library/react';
12+
export { render };

packages/clerk-js/src/ui/common/redirects.test.ts packages/clerk-js/src/ui/common/__tests__/redirects.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { buildMagicLinkRedirectUrl, buildSSOCallbackURL } from './redirects';
1+
import { buildMagicLinkRedirectUrl, buildSSOCallbackURL } from '../redirects';
22

33
describe('buildMagicLinkRedirectUrl(routing, baseUrl)', () => {
44
it('handles empty routing strategy based routing ', function () {

packages/clerk-js/src/ui/common/verification.test.ts packages/clerk-js/src/ui/common/__tests__/verification.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { ClerkAPIResponseError } from '../../core/resources/Error';
2-
import { isVerificationExpiredError, VerificationErrorMessage, verificationErrorMessage } from './verification';
1+
import { ClerkAPIResponseError } from '../../../core/resources/Error';
2+
import { isVerificationExpiredError, VerificationErrorMessage, verificationErrorMessage } from '../verification';
33

44
describe('verification utils', () => {
55
describe('verificationErrorMessage', () => {

packages/clerk-js/src/ui/common/withRedirectToHome.test.tsx packages/clerk-js/src/ui/common/__tests__/withRedirectToHome.test.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { render, screen } from '@clerk/shared/testUtils';
22
import { EnvironmentResource } from '@clerk/types';
33
import React from 'react';
44

5-
import { AuthConfig, DisplayConfig } from '../../core/resources';
6-
import { CoreSessionContext, useEnvironment } from '../../ui/contexts';
7-
import { withRedirectToHome } from './withRedirectToHome';
5+
import { AuthConfig, DisplayConfig } from '../../../core/resources';
6+
import { CoreSessionContext, useEnvironment } from '../../contexts';
7+
import { withRedirectToHome } from '../withRedirectToHome';
88

99
const mockNavigate = jest.fn();
1010
jest.mock('ui/hooks', () => ({

packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import { ClerkAPIError, SignInCreateParams } from '@clerk/types';
22
import React from 'react';
33

44
import { clerkInvalidFAPIResponse } from '../../../core/errors';
5-
import { getClerkQueryParam } from '../../../utils/getClerkQueryParam';
6-
import { ERROR_CODES, getIdentifierControlDisplayValues } from '../../common/constants';
7-
import { withRedirectToHome } from '../../common/withRedirectToHome';
5+
import { getClerkQueryParam } from '../../../utils';
6+
import { ERROR_CODES, getIdentifierControlDisplayValues, withRedirectToHome } from '../../common';
87
import { useCoreClerk, useCoreSignIn, useEnvironment, useSignInContext } from '../../contexts';
98
import { Col, descriptors, Flow, localizationKeys } from '../../customizables';
109
import {
@@ -15,9 +14,9 @@ import {
1514
Header,
1615
LoadingCard,
1716
SocialButtonsReversibleContainerWithDivider,
17+
useCardState,
1818
withCardStateProvider,
1919
} from '../../elements';
20-
import { useCardState } from '../../elements/contexts';
2120
import { useLoadingStatus, useNavigate } from '../../hooks';
2221
import { useSupportEmail } from '../../hooks/useSupportEmail';
2322
import { buildRequest, FormControlState, handleError, isMobileDevice, useFormControl } from '../../utils';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { describe, it } from '@jest/globals';
2+
import React from 'react';
3+
4+
import { bindCreateFixtures, render } from '../../../../testUtils';
5+
import { SignInAccountSwitcher } from '../SignInAccountSwitcher';
6+
7+
const { createFixtures } = bindCreateFixtures('SignIn');
8+
9+
describe('SignInAccountSwitcher', () => {
10+
it('renders the component', async () => {
11+
const { wrapper } = await createFixtures();
12+
render(<SignInAccountSwitcher />, { wrapper });
13+
});
14+
15+
const initConfig = createFixtures.config(f => {
16+
f.withMultiSessionMode();
17+
f.withUser({ first_name: 'Nick', last_name: 'Kouk', email_addresses: ['test1@clerk.dev'] });
18+
f.withUser({ first_name: 'Mike', last_name: 'Lamar', email_addresses: ['test2@clerk.dev'] });
19+
f.withUser({ first_name: 'Graciela', last_name: 'Brennan', email_addresses: ['test3@clerk.dev'] });
20+
});
21+
22+
it('renders a list of buttons with all signed in accounts', async () => {
23+
const { wrapper } = await createFixtures(initConfig);
24+
const { getByText } = render(<SignInAccountSwitcher />, { wrapper });
25+
expect(getByText('Nick Kouk')).toBeDefined();
26+
expect(getByText('Mike Lamar')).toBeDefined();
27+
expect(getByText('Graciela Brennan')).toBeDefined();
28+
});
29+
30+
it('sets an active session when user clicks an already logged in account from the list', async () => {
31+
const { wrapper, fixtures } = await createFixtures(initConfig);
32+
fixtures.clerk.setActive.mockReturnValueOnce(Promise.resolve());
33+
const { userEvent, getByText } = render(<SignInAccountSwitcher />, { wrapper });
34+
await userEvent.click(getByText('Nick Kouk'));
35+
expect(fixtures.clerk.setActive).toHaveBeenCalled();
36+
});
37+
38+
// this one uses the windowNavigate method. we need to mock it correctly
39+
it.skip('navigates to SignInStart component if user clicks on "Add account" button', async () => {
40+
const { wrapper, fixtures } = await createFixtures(initConfig);
41+
const { userEvent, getByText } = render(<SignInAccountSwitcher />, { wrapper });
42+
await userEvent.click(getByText('Add account'));
43+
expect(fixtures.router.navigate).toHaveBeenCalled();
44+
});
45+
46+
it('signs out when user clicks on "Sign out of all accounts"', async () => {
47+
const { wrapper, fixtures } = await createFixtures(initConfig);
48+
const { userEvent, getByText } = render(<SignInAccountSwitcher />, { wrapper });
49+
expect(getByText('Nick Kouk')).toBeDefined();
50+
expect(getByText('Mike Lamar')).toBeDefined();
51+
expect(getByText('Graciela Brennan')).toBeDefined();
52+
await userEvent.click(getByText('Sign out of all accounts'));
53+
expect(fixtures.clerk.signOut).toHaveBeenCalled();
54+
});
55+
});

0 commit comments

Comments
 (0)