mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
refactor: client jest -> vitest (#62177)
This commit is contained in:
committed by
GitHub
parent
c7354cff89
commit
881dfd8f78
@@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { GatsbyLinkProps } from 'gatsby';
|
||||||
|
import { vi } from 'vitest';
|
||||||
|
import gatsby from 'gatsby';
|
||||||
|
|
||||||
|
import envData from '../config/env.json';
|
||||||
|
const { clientLocale } = envData;
|
||||||
|
|
||||||
|
export const navigate = vi.fn();
|
||||||
|
export const graphql = vi.fn();
|
||||||
|
export const Link = vi
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(({ to, ...rest }: GatsbyLinkProps<undefined | boolean>) =>
|
||||||
|
React.createElement('a', { ...rest, href: to })
|
||||||
|
);
|
||||||
|
export const withPrefix = vi.fn().mockImplementation((path: string) => {
|
||||||
|
const pathPrefix = clientLocale === 'english' ? '' : '/' + clientLocale;
|
||||||
|
return pathPrefix + path;
|
||||||
|
});
|
||||||
|
export const StaticQuery = vi.fn();
|
||||||
|
export const useStaticQuery = vi.fn();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// ...existing code...
|
||||||
|
// spread the actual gatsby module to keep other exports working
|
||||||
|
...gatsby,
|
||||||
|
navigate,
|
||||||
|
graphql,
|
||||||
|
Link,
|
||||||
|
withPrefix,
|
||||||
|
StaticQuery,
|
||||||
|
useStaticQuery
|
||||||
|
};
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const reactI18next = jest.genMockFromModule('react-i18next');
|
|
||||||
|
|
||||||
// modified from https://github.com/i18next/react-i18next/blob/master/example/test-jest/src/__mocks__/react-i18next.js
|
// modified from https://github.com/i18next/react-i18next/blob/master/example/test-jest/src/__mocks__/react-i18next.js
|
||||||
const hasChildren = node =>
|
const hasChildren = node =>
|
||||||
node && (node.children || (node.props && node.props.children));
|
node && (node.children || (node.props && node.props.children));
|
||||||
@@ -58,9 +56,4 @@ const Trans = ({ children }) =>
|
|||||||
<Component t={() => ''} {...props} />
|
<Component t={() => ''} {...props} />
|
||||||
); */
|
); */
|
||||||
|
|
||||||
// reactI18next.translate = translate;
|
module.exports = { withTranslation, useTranslation, Trans };
|
||||||
reactI18next.withTranslation = withTranslation;
|
|
||||||
reactI18next.useTranslation = useTranslation;
|
|
||||||
reactI18next.Trans = Trans;
|
|
||||||
|
|
||||||
module.exports = reactI18next;
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/display-name
|
||||||
|
export default () => <div>Spinner</div>;
|
||||||
+25
-14
@@ -1,5 +1,9 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { setup } from 'jest-json-schema-extended';
|
import { dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
|
||||||
import { availableLangs, LangNames, LangCodes } from '../../shared/config/i18n';
|
import { availableLangs, LangNames, LangCodes } from '../../shared/config/i18n';
|
||||||
import {
|
import {
|
||||||
catalogSuperBlocks,
|
catalogSuperBlocks,
|
||||||
@@ -7,8 +11,6 @@ import {
|
|||||||
} from '../../shared/config/curriculum';
|
} from '../../shared/config/curriculum';
|
||||||
import intro from './locales/english/intro.json';
|
import intro from './locales/english/intro.json';
|
||||||
|
|
||||||
setup();
|
|
||||||
|
|
||||||
interface Intro {
|
interface Intro {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -41,6 +43,9 @@ const filesThatShouldExist = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
const path = `${__dirname}/locales`;
|
const path = `${__dirname}/locales`;
|
||||||
|
|
||||||
describe('Locale tests:', () => {
|
describe('Locale tests:', () => {
|
||||||
@@ -77,19 +82,25 @@ describe('Intro file structure tests:', () => {
|
|||||||
const typedIntro = intro as unknown as Intro;
|
const typedIntro = intro as unknown as Intro;
|
||||||
const superblocks = Object.values(SuperBlocks);
|
const superblocks = Object.values(SuperBlocks);
|
||||||
for (const superBlock of superblocks) {
|
for (const superBlock of superblocks) {
|
||||||
expect(typeof typedIntro[superBlock].title).toBe('string');
|
test(`superBlock ${superBlock} has required properties`, () => {
|
||||||
|
expect(typeof typedIntro[superBlock].title).toBe('string');
|
||||||
|
|
||||||
|
// catalog superblocks should have a summary
|
||||||
|
if (catalogSuperBlocks.includes(superBlock)) {
|
||||||
|
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
|
||||||
|
}
|
||||||
|
|
||||||
// catalog superblocks should have a summary
|
|
||||||
if (catalogSuperBlocks.includes(superBlock)) {
|
|
||||||
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
|
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
|
||||||
}
|
expect(typedIntro[superBlock].blocks).toBeInstanceOf(Object);
|
||||||
|
const blocks = Object.keys(typedIntro[superBlock].blocks);
|
||||||
expect(typedIntro[superBlock].intro).toBeInstanceOf(Array);
|
blocks.forEach(block => {
|
||||||
expect(typedIntro[superBlock].blocks).toBeInstanceOf(Object);
|
expect(typeof typedIntro[superBlock].blocks[block].title).toBe(
|
||||||
const blocks = Object.keys(typedIntro[superBlock].blocks);
|
'string'
|
||||||
blocks.forEach(block => {
|
);
|
||||||
expect(typeof typedIntro[superBlock].blocks[block].title).toBe('string');
|
expect(typedIntro[superBlock].blocks[block].intro).toBeInstanceOf(
|
||||||
expect(typedIntro[superBlock].blocks[block].intro).toBeInstanceOf(Array);
|
Array
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"serve-ci": "serve -l 8000 -c serve.json public",
|
"serve-ci": "serve -l 8000 -c serve.json public",
|
||||||
"prestand-alone": "pnpm run prebuild",
|
"prestand-alone": "pnpm run prebuild",
|
||||||
"stand-alone": "gatsby develop",
|
"stand-alone": "gatsby develop",
|
||||||
|
"test": "vitest",
|
||||||
"validate-keys": "tsx --tsconfig ../tsconfig.json ../tools/scripts/lint/validate-keys"
|
"validate-keys": "tsx --tsconfig ../tsconfig.json ../tools/scripts/lint/validate-keys"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -132,7 +133,9 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||||
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "12.1.5",
|
||||||
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
"@total-typescript/ts-reset": "^0.5.0",
|
"@total-typescript/ts-reset": "^0.5.0",
|
||||||
"@types/canvas-confetti": "^1.6.0",
|
"@types/canvas-confetti": "^1.6.0",
|
||||||
"@types/gatsbyjs__reach-router": "1.3.0",
|
"@types/gatsbyjs__reach-router": "1.3.0",
|
||||||
@@ -156,6 +159,7 @@
|
|||||||
"@types/sanitize-html": "^2.8.0",
|
"@types/sanitize-html": "^2.8.0",
|
||||||
"@types/store": "^2.0.2",
|
"@types/store": "^2.0.2",
|
||||||
"@types/validator": "^13.7.12",
|
"@types/validator": "^13.7.12",
|
||||||
|
"@vitest/ui": "^3.2.4",
|
||||||
"autoprefixer": "10.4.17",
|
"autoprefixer": "10.4.17",
|
||||||
"babel-plugin-macros": "3.1.0",
|
"babel-plugin-macros": "3.1.0",
|
||||||
"core-js": "2.6.12",
|
"core-js": "2.6.12",
|
||||||
@@ -170,6 +174,7 @@
|
|||||||
"react-test-renderer": "17.0.2",
|
"react-test-renderer": "17.0.2",
|
||||||
"redux-saga-test-plan": "4.0.6",
|
"redux-saga-test-plan": "4.0.6",
|
||||||
"serve": "13.0.4",
|
"serve": "13.0.4",
|
||||||
|
"vitest": "^3.2.4",
|
||||||
"webpack": "5.90.3"
|
"webpack": "5.90.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,188 +0,0 @@
|
|||||||
interface MockChallengeNodes {
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: string;
|
|
||||||
blockName: string;
|
|
||||||
};
|
|
||||||
id: string;
|
|
||||||
block: string;
|
|
||||||
title: string;
|
|
||||||
superBlock: string;
|
|
||||||
dashedName: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockChallengeNodes: MockChallengeNodes[] = [
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-one/block-a/challenge-one',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'a',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-one',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-one/block-a/challenge-two',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'b',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge Two',
|
|
||||||
superBlock: 'super-block-one',
|
|
||||||
dashedName: 'challenge-two'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-one/block-b/challenge-one',
|
|
||||||
blockName: 'Block B'
|
|
||||||
},
|
|
||||||
id: 'c',
|
|
||||||
block: 'block-b',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-one',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-one/block-b/challenge-two',
|
|
||||||
blockName: 'Block B'
|
|
||||||
},
|
|
||||||
|
|
||||||
id: 'd',
|
|
||||||
block: 'block-b',
|
|
||||||
title: 'Challenge Two',
|
|
||||||
superBlock: 'super-block-one',
|
|
||||||
dashedName: 'challenge-two'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-one/block-c/challenge-one',
|
|
||||||
blockName: 'Block C'
|
|
||||||
},
|
|
||||||
id: 'e',
|
|
||||||
block: 'block-c',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-one',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-two/block-a/challenge-one',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'f',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-two',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-two/block-a/challenge-two',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'g',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge Two',
|
|
||||||
superBlock: 'super-block-two',
|
|
||||||
dashedName: 'challenge-two'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-two/block-b/challenge-one',
|
|
||||||
blockName: 'Block B'
|
|
||||||
},
|
|
||||||
id: 'h',
|
|
||||||
block: 'block-b',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-two',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-two/block-b/challenge-two',
|
|
||||||
blockName: 'Block B'
|
|
||||||
},
|
|
||||||
id: 'i',
|
|
||||||
block: 'block-b',
|
|
||||||
title: 'Challenge Two',
|
|
||||||
superBlock: 'super-block-two',
|
|
||||||
dashedName: 'challenge-two'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-three/block-a/challenge-one',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'j',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-three',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-three/block-c/challenge-two',
|
|
||||||
blockName: 'Block C'
|
|
||||||
},
|
|
||||||
id: 'k',
|
|
||||||
block: 'block-c',
|
|
||||||
title: 'Challenge Two',
|
|
||||||
superBlock: 'super-block-three',
|
|
||||||
dashedName: 'challenge-two'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-three/block-c/challenge-three',
|
|
||||||
blockName: 'Block C'
|
|
||||||
},
|
|
||||||
id: 'l',
|
|
||||||
block: 'block-c',
|
|
||||||
title: 'Challenge Three',
|
|
||||||
superBlock: 'super-block-three',
|
|
||||||
dashedName: 'challenge-three'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
challenge: {
|
|
||||||
fields: {
|
|
||||||
slug: '/super-block-four/block-a/challenge-one',
|
|
||||||
blockName: 'Block A'
|
|
||||||
},
|
|
||||||
id: 'm',
|
|
||||||
block: 'block-a',
|
|
||||||
title: 'Challenge One',
|
|
||||||
superBlock: 'super-block-four',
|
|
||||||
dashedName: 'challenge-one'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export default mockChallengeNodes;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default {};
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { GatsbyLinkProps } from 'gatsby';
|
|
||||||
const gatsby: NodeModule = jest.requireActual('gatsby');
|
|
||||||
|
|
||||||
import envData from '../../config/env.json';
|
|
||||||
|
|
||||||
const { clientLocale } = envData;
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
...gatsby,
|
|
||||||
navigate: jest.fn(),
|
|
||||||
graphql: jest.fn(),
|
|
||||||
Link: jest.fn().mockImplementation(
|
|
||||||
// these props are invalid for an `a` tag
|
|
||||||
({ to, ...rest }: GatsbyLinkProps<undefined | boolean>) =>
|
|
||||||
React.createElement('a', {
|
|
||||||
...rest,
|
|
||||||
href: to
|
|
||||||
})
|
|
||||||
),
|
|
||||||
withPrefix: jest.fn().mockImplementation((path: string) => {
|
|
||||||
const pathPrefix = clientLocale === 'english' ? '' : '/' + clientLocale;
|
|
||||||
return pathPrefix + path;
|
|
||||||
}),
|
|
||||||
StaticQuery: jest.fn(),
|
|
||||||
useStaticQuery: jest.fn()
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default {};
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import {
|
import {
|
||||||
wrapHandledError,
|
wrapHandledError,
|
||||||
unwrapHandledError
|
unwrapHandledError
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import callGA, { GAevent } from './call-ga';
|
|
||||||
import TagManager from '.';
|
|
||||||
|
|
||||||
jest.mock('.', () => ({
|
|
||||||
dataLayer: jest.fn()
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('callGA function', () => {
|
|
||||||
it('calls TagManager dataLayer with the same arguments', () => {
|
|
||||||
const eventDataMock: GAevent = {
|
|
||||||
event: 'donation',
|
|
||||||
action: 'Donate Page Stripe Payment Submission',
|
|
||||||
duration: 'month',
|
|
||||||
amount: 500,
|
|
||||||
completed_challenges: 100,
|
|
||||||
completed_challenges_session: 10,
|
|
||||||
isSignedIn: true
|
|
||||||
};
|
|
||||||
callGA(eventDataMock);
|
|
||||||
expect(TagManager.dataLayer).toHaveBeenCalledWith({
|
|
||||||
dataLayer: eventDataMock
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -2,13 +2,14 @@
|
|||||||
// @ts-nocheck Likely need to not use ShallowRenderer
|
// @ts-nocheck Likely need to not use ShallowRenderer
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ShallowRenderer from 'react-test-renderer/shallow';
|
import ShallowRenderer from 'react-test-renderer/shallow';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import envData from '../../config/env.json';
|
import envData from '../../config/env.json';
|
||||||
|
|
||||||
import { ShowSettings } from './show-settings';
|
import { ShowSettings } from './show-settings';
|
||||||
|
|
||||||
const { apiLocation } = envData as Record<string, string>;
|
const { apiLocation } = envData as Record<string, string>;
|
||||||
|
|
||||||
jest.mock('../analytics');
|
vi.mock('../analytics');
|
||||||
|
|
||||||
describe('<ShowSettings />', () => {
|
describe('<ShowSettings />', () => {
|
||||||
it('renders to the DOM when user is logged in', () => {
|
it('renders to the DOM when user is logged in', () => {
|
||||||
@@ -34,24 +35,24 @@ describe('<ShowSettings />', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigate = jest.fn();
|
const navigate = vi.fn();
|
||||||
const loggedInProps = {
|
const loggedInProps = {
|
||||||
createFlashMessage: jest.fn(),
|
createFlashMessage: vi.fn(),
|
||||||
hardGoTo: jest.fn(),
|
hardGoTo: vi.fn(),
|
||||||
isSignedIn: true,
|
isSignedIn: true,
|
||||||
navigate: navigate,
|
navigate: navigate,
|
||||||
showLoading: false,
|
showLoading: false,
|
||||||
submitNewAbout: jest.fn(),
|
submitNewAbout: vi.fn(),
|
||||||
toggleTheme: jest.fn(),
|
toggleTheme: vi.fn(),
|
||||||
updateSocials: jest.fn(),
|
updateSocials: vi.fn(),
|
||||||
updateIsHonest: jest.fn(),
|
updateIsHonest: vi.fn(),
|
||||||
updatePortfolio: jest.fn(),
|
updatePortfolio: vi.fn(),
|
||||||
updateQuincyEmail: jest.fn(),
|
updateQuincyEmail: vi.fn(),
|
||||||
user: {
|
user: {
|
||||||
about: '',
|
about: '',
|
||||||
completedChallenges: []
|
completedChallenges: []
|
||||||
},
|
},
|
||||||
verifyCert: jest.fn()
|
verifyCert: vi.fn()
|
||||||
};
|
};
|
||||||
const loggedOutProps = { ...loggedInProps };
|
const loggedOutProps = { ...loggedInProps };
|
||||||
loggedOutProps.isSignedIn = false;
|
loggedOutProps.isSignedIn = false;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<Footer /> matches snapshot 1`] = `
|
exports[`<Footer /> > matches snapshot 1`] = `
|
||||||
<footer
|
<footer
|
||||||
className="site-footer"
|
className="site-footer"
|
||||||
>
|
>
|
||||||
@@ -342,7 +342,7 @@ exports[`<Footer /> matches snapshot 1`] = `
|
|||||||
<img
|
<img
|
||||||
alt="Download on the App Store"
|
alt="Download on the App Store"
|
||||||
lang="en"
|
lang="en"
|
||||||
src={{}}
|
src="/src/assets/images/footer-ads/apple-store-badge.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -355,7 +355,7 @@ exports[`<Footer /> matches snapshot 1`] = `
|
|||||||
<img
|
<img
|
||||||
alt="Get it on Google Play"
|
alt="Get it on Google Play"
|
||||||
lang="en"
|
lang="en"
|
||||||
src={{}}
|
src="/src/assets/images/footer-ads/google-play-badge.svg"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import Footer from '.';
|
import Footer from '.';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { create, ReactTestRendererJSON } from 'react-test-renderer';
|
import { create, ReactTestRendererJSON } from 'react-test-renderer';
|
||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
import AuthOrProfile from './components/auth-or-profile';
|
import AuthOrProfile from './components/auth-or-profile';
|
||||||
|
|
||||||
const defaultUserProps = {
|
const defaultUserProps = {
|
||||||
@@ -37,7 +38,7 @@ const topDonatingContributorUserProps = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../../analytics');
|
vi.mock('../../analytics');
|
||||||
|
|
||||||
describe('<AuthOrProfile />', () => {
|
describe('<AuthOrProfile />', () => {
|
||||||
it('has avatar with default border for default users', () => {
|
it('has avatar with default border for default users', () => {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
import { createStore } from '../../redux/create-store';
|
import { createStore } from '../../redux/create-store';
|
||||||
|
|
||||||
import Intro from '.';
|
import Intro from '.';
|
||||||
|
|
||||||
jest.mock('../../analytics');
|
vi.mock('../../analytics');
|
||||||
|
vi.mock('../../utils/get-words');
|
||||||
|
|
||||||
function renderWithRedux(
|
function renderWithRedux(
|
||||||
ui: JSX.Element,
|
ui: JSX.Element,
|
||||||
@@ -45,12 +47,12 @@ const loggedInProps = {
|
|||||||
completedChallengeCount: 0,
|
completedChallengeCount: 0,
|
||||||
isSignedIn: true,
|
isSignedIn: true,
|
||||||
name: 'Development User',
|
name: 'Development User',
|
||||||
navigate: () => jest.fn(),
|
navigate: () => vi.fn(),
|
||||||
pending: false,
|
pending: false,
|
||||||
slug: '/',
|
slug: '/',
|
||||||
username: 'DevelopmentUser',
|
username: 'DevelopmentUser',
|
||||||
isDonating: false,
|
isDonating: false,
|
||||||
onLearnDonationAlertClick: () => jest.fn()
|
onLearnDonationAlertClick: () => vi.fn()
|
||||||
};
|
};
|
||||||
|
|
||||||
const loggedOutProps = {
|
const loggedOutProps = {
|
||||||
@@ -58,10 +60,10 @@ const loggedOutProps = {
|
|||||||
completedChallengeCount: 0,
|
completedChallengeCount: 0,
|
||||||
isSignedIn: false,
|
isSignedIn: false,
|
||||||
name: '',
|
name: '',
|
||||||
navigate: () => jest.fn(),
|
navigate: () => vi.fn(),
|
||||||
pending: false,
|
pending: false,
|
||||||
slug: '/',
|
slug: '/',
|
||||||
username: '',
|
username: '',
|
||||||
isDonating: false,
|
isDonating: false,
|
||||||
onLearnDonationAlertClick: () => jest.fn()
|
onLearnDonationAlertClick: () => vi.fn()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, act, screen } from '@testing-library/react';
|
import { render, act, screen } from '@testing-library/react';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
import OfflineWarning from './offline-warning';
|
import OfflineWarning from './offline-warning';
|
||||||
|
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
|
||||||
describe('<OfflineWarning />', () => {
|
describe('<OfflineWarning />', () => {
|
||||||
it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
|
it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
|
<OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
|
||||||
);
|
);
|
||||||
act(() => jest.runAllTimers());
|
act(() => void vi.runAllTimers());
|
||||||
expect(container).toBeEmptyDOMElement();
|
expect(container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ describe('<OfflineWarning />', () => {
|
|||||||
isSignedIn={true}
|
isSignedIn={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
act(() => jest.runAllTimers());
|
act(() => void vi.runAllTimers());
|
||||||
expect(screen.getByText('misc.offline')).toBeInTheDocument();
|
expect(screen.getByText('misc.offline')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ describe('<OfflineWarning />', () => {
|
|||||||
isSignedIn={true}
|
isSignedIn={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
act(() => jest.runAllTimers());
|
act(() => void vi.runAllTimers());
|
||||||
expect(screen.getByText('placeholder').tagName).toBe('A');
|
expect(screen.getByText('placeholder').tagName).toBe('A');
|
||||||
expect(screen.getByText('placeholder')).toHaveAttribute(
|
expect(screen.getByText('placeholder')).toHaveAttribute(
|
||||||
'href',
|
'href',
|
||||||
@@ -50,7 +51,7 @@ describe('<OfflineWarning />', () => {
|
|||||||
isSignedIn={false}
|
isSignedIn={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
act(() => jest.runAllTimers());
|
act(() => void vi.runAllTimers());
|
||||||
expect(container).toBeEmptyDOMElement();
|
expect(container).toBeEmptyDOMElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ describe('<OfflineWarning />', () => {
|
|||||||
isSignedIn={true}
|
isSignedIn={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
act(() => jest.runAllTimers());
|
act(() => void vi.runAllTimers());
|
||||||
expect(screen.getByText('misc.offline')).toBeInTheDocument();
|
expect(screen.getByText('misc.offline')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import { render, waitFor } from '@testing-library/react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { I18nextProvider } from 'react-i18next';
|
import { I18nextProvider } from 'react-i18next';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { describe, vi, test, expect } from 'vitest';
|
||||||
|
|
||||||
import { i18nextCodes } from '../../../shared/config/i18n';
|
import { i18nextCodes } from '../../../shared/config/i18n';
|
||||||
import i18nTestConfig from '../../i18n/config-for-tests';
|
import i18nTestConfig from '../../i18n/config-for-tests';
|
||||||
import { createStore } from '../redux/create-store';
|
import { createStore } from '../redux/create-store';
|
||||||
import AppMountNotifier from './app-mount-notifier';
|
import AppMountNotifier from './app-mount-notifier';
|
||||||
|
|
||||||
jest.unmock('react-i18next');
|
vi.unmock('react-i18next');
|
||||||
|
vi.mock('../utils/get-words');
|
||||||
|
|
||||||
type Language = keyof typeof i18nextCodes;
|
type Language = keyof typeof i18nextCodes;
|
||||||
type LanguagePair = [string, string];
|
type LanguagePair = [string, string];
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
import createLanguageRedirect from './create-language-redirect';
|
import createLanguageRedirect from './create-language-redirect';
|
||||||
|
|
||||||
describe('createLanguageRedirect for clientLocale === english', () => {
|
describe('createLanguageRedirect for clientLocale === english', () => {
|
||||||
@@ -17,8 +19,6 @@ describe('createLanguageRedirect for clientLocale === english', () => {
|
|||||||
const dothrakiPageURL =
|
const dothrakiPageURL =
|
||||||
'https://www.freecodecamp.org/dothraki/learn/responsive-web-design/basic-html-and-html5/inform-with-the-paragraph-element';
|
'https://www.freecodecamp.org/dothraki/learn/responsive-web-design/basic-html-and-html5/inform-with-the-paragraph-element';
|
||||||
|
|
||||||
const originalLocation = window.location;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Object.defineProperty(window, 'location', {
|
Object.defineProperty(window, 'location', {
|
||||||
writable: true,
|
writable: true,
|
||||||
@@ -26,10 +26,6 @@ describe('createLanguageRedirect for clientLocale === english', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
window.location = originalLocation;
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{ lang: 'english', url: currentPageURL },
|
{ lang: 'english', url: currentPageURL },
|
||||||
{ lang: 'chinese', url: chinesePageURL },
|
{ lang: 'chinese', url: chinesePageURL },
|
||||||
@@ -60,8 +56,6 @@ describe('createLanguageRedirect for clientLocale === english', () => {
|
|||||||
'https://www.freecodecamp.org/chinese-traditional/settings';
|
'https://www.freecodecamp.org/chinese-traditional/settings';
|
||||||
const dothrakiPageURL = 'https://www.freecodecamp.org/dothraki/settings';
|
const dothrakiPageURL = 'https://www.freecodecamp.org/dothraki/settings';
|
||||||
|
|
||||||
const originalLocation = window.location;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Object.defineProperty(window, 'location', {
|
Object.defineProperty(window, 'location', {
|
||||||
writable: true,
|
writable: true,
|
||||||
@@ -69,10 +63,6 @@ describe('createLanguageRedirect for clientLocale === english', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
window.location = originalLocation;
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{ lang: 'english', url: currentPageURL },
|
{ lang: 'english', url: currentPageURL },
|
||||||
{ lang: 'chinese', url: chinesePageURL },
|
{ lang: 'chinese', url: chinesePageURL },
|
||||||
@@ -113,8 +103,6 @@ describe('createLanguageRedirect for clientLocale === chinese', () => {
|
|||||||
const dothrakiPageURL =
|
const dothrakiPageURL =
|
||||||
'https://www.freecodecamp.org/dothraki/learn/responsive-web-design/basic-html-and-html5/inform-with-the-paragraph-element';
|
'https://www.freecodecamp.org/dothraki/learn/responsive-web-design/basic-html-and-html5/inform-with-the-paragraph-element';
|
||||||
|
|
||||||
const originalLocation = window.location;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Object.defineProperty(window, 'location', {
|
Object.defineProperty(window, 'location', {
|
||||||
writable: true,
|
writable: true,
|
||||||
@@ -122,10 +110,6 @@ describe('createLanguageRedirect for clientLocale === chinese', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
window.location = originalLocation;
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{ lang: 'chinese', url: currentPageURL },
|
{ lang: 'chinese', url: currentPageURL },
|
||||||
{ lang: 'english', url: englishPageURL },
|
{ lang: 'english', url: englishPageURL },
|
||||||
@@ -156,8 +140,6 @@ describe('createLanguageRedirect for clientLocale === chinese', () => {
|
|||||||
'https://www.freecodecamp.org/chinese-traditional/settings';
|
'https://www.freecodecamp.org/chinese-traditional/settings';
|
||||||
const dothrakiPageURL = 'https://www.freecodecamp.org/dothraki/settings';
|
const dothrakiPageURL = 'https://www.freecodecamp.org/dothraki/settings';
|
||||||
|
|
||||||
const originalLocation = window.location;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Object.defineProperty(window, 'location', {
|
Object.defineProperty(window, 'location', {
|
||||||
writable: true,
|
writable: true,
|
||||||
@@ -165,10 +147,6 @@ describe('createLanguageRedirect for clientLocale === chinese', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
window.location = originalLocation;
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{ lang: 'chinese', url: currentPageURL },
|
{ lang: 'chinese', url: currentPageURL },
|
||||||
{ lang: 'english', url: englishPageURL },
|
{ lang: 'english', url: englishPageURL },
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
import {
|
import {
|
||||||
editorValidator,
|
editorValidator,
|
||||||
fCCValidator,
|
fCCValidator,
|
||||||
@@ -6,146 +7,148 @@ import {
|
|||||||
pathValidator
|
pathValidator
|
||||||
} from './form-validators';
|
} from './form-validators';
|
||||||
|
|
||||||
test('editorValidator', () => {
|
describe('Form validators', () => {
|
||||||
const editorAddresses = [
|
test('editorValidator', () => {
|
||||||
'repl.it/@username',
|
const editorAddresses = [
|
||||||
'repl.it/join/username',
|
'repl.it/@username',
|
||||||
'replit.com/@username',
|
'repl.it/join/username',
|
||||||
'replit.com/join/username',
|
'replit.com/@username',
|
||||||
'glitch.com/edit/#!',
|
'replit.com/join/username',
|
||||||
'codesandbox.io/s/',
|
'glitch.com/edit/#!',
|
||||||
'https://github.com',
|
'codesandbox.io/s/',
|
||||||
'https://glitch.com/edit/#!/project',
|
'https://github.com',
|
||||||
'https://glitch.com/edit/#!'
|
'https://glitch.com/edit/#!/project',
|
||||||
];
|
'https://glitch.com/edit/#!'
|
||||||
|
];
|
||||||
|
|
||||||
const nonEditorAddresses = [
|
const nonEditorAddresses = [
|
||||||
'example.com',
|
'example.com',
|
||||||
'http://example.com',
|
'http://example.com',
|
||||||
'https://example.com',
|
'https://example.com',
|
||||||
'http://repl.it',
|
'http://repl.it',
|
||||||
'http://glitch.com',
|
'http://glitch.com',
|
||||||
'https://repl.it/home'
|
'https://repl.it/home'
|
||||||
];
|
];
|
||||||
|
|
||||||
editorAddresses.forEach(address => {
|
editorAddresses.forEach(address => {
|
||||||
expect(editorValidator(address)).not.toBeNull();
|
expect(editorValidator(address)).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
nonEditorAddresses.forEach(address => {
|
||||||
|
expect(editorValidator(address)).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
nonEditorAddresses.forEach(address => {
|
test('fCCValidator', () => {
|
||||||
expect(editorValidator(address)).toBeNull();
|
const fCCAddresses = [
|
||||||
});
|
'codepen.io/freecodecamp',
|
||||||
});
|
'freecodecamp.rocks',
|
||||||
|
'github.com/freecodecamp',
|
||||||
test('fCCValidator', () => {
|
'.freecodecamp.org',
|
||||||
const fCCAddresses = [
|
'https://codepen.io/freecodecamp',
|
||||||
'codepen.io/freecodecamp',
|
'https://freecodecamp.rocks',
|
||||||
'freecodecamp.rocks',
|
'https://github.com/freeCodeCamp',
|
||||||
'github.com/freecodecamp',
|
'https://www.freecodecamp.org'
|
||||||
'.freecodecamp.org',
|
];
|
||||||
'https://codepen.io/freecodecamp',
|
|
||||||
'https://freecodecamp.rocks',
|
const nonFCCAddresses = [
|
||||||
'https://github.com/freeCodeCamp',
|
'example.com',
|
||||||
'https://www.freecodecamp.org'
|
'http://example.com',
|
||||||
];
|
'https://example.com',
|
||||||
|
'http://codepen.io',
|
||||||
const nonFCCAddresses = [
|
'https://github.com',
|
||||||
'example.com',
|
'https://codepen.io/editor',
|
||||||
'http://example.com',
|
'https://github.com/repo'
|
||||||
'https://example.com',
|
];
|
||||||
'http://codepen.io',
|
|
||||||
'https://github.com',
|
fCCAddresses.forEach(address => {
|
||||||
'https://codepen.io/editor',
|
expect(fCCValidator(address)).not.toBeNull();
|
||||||
'https://github.com/repo'
|
});
|
||||||
];
|
|
||||||
|
nonFCCAddresses.forEach(address => {
|
||||||
fCCAddresses.forEach(address => {
|
expect(fCCValidator(address)).toBeNull();
|
||||||
expect(fCCValidator(address)).not.toBeNull();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
nonFCCAddresses.forEach(address => {
|
test('localhostValidator', () => {
|
||||||
expect(fCCValidator(address)).toBeNull();
|
const privateAddresses = [
|
||||||
});
|
'http://localhost:3000',
|
||||||
});
|
'https://localhost:3000',
|
||||||
|
'http://127.0.0.1',
|
||||||
test('localhostValidator', () => {
|
'http://127.0.0.1:3000',
|
||||||
const privateAddresses = [
|
'https://127.0.0.1',
|
||||||
'http://localhost:3000',
|
'https://127.0.0.1:3000',
|
||||||
'https://localhost:3000',
|
'http://[::1]:3000'
|
||||||
'http://127.0.0.1',
|
];
|
||||||
'http://127.0.0.1:3000',
|
|
||||||
'https://127.0.0.1',
|
const publicAddresses = [
|
||||||
'https://127.0.0.1:3000',
|
'http://localhost.com',
|
||||||
'http://[::1]:3000'
|
'http://example.com',
|
||||||
];
|
'http://example.com:3000',
|
||||||
|
'https://example.com',
|
||||||
const publicAddresses = [
|
'https://example.com:3000'
|
||||||
'http://localhost.com',
|
];
|
||||||
'http://example.com',
|
|
||||||
'http://example.com:3000',
|
privateAddresses.forEach(address => {
|
||||||
'https://example.com',
|
expect(localhostValidator(address)).not.toBeNull();
|
||||||
'https://example.com:3000'
|
});
|
||||||
];
|
|
||||||
|
publicAddresses.forEach(address => {
|
||||||
privateAddresses.forEach(address => {
|
expect(localhostValidator(address)).toBeNull();
|
||||||
expect(localhostValidator(address)).not.toBeNull();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
publicAddresses.forEach(address => {
|
test('httpValidator', () => {
|
||||||
expect(localhostValidator(address)).toBeNull();
|
const allowedHttpAddresses = ['http://[::1]:3000', 'http://localhost:3000'];
|
||||||
});
|
|
||||||
});
|
const disallowedHttpAddresses = [
|
||||||
|
'http://example.com',
|
||||||
test('httpValidator', () => {
|
'http://localhost.com'
|
||||||
const allowedHttpAddresses = ['http://[::1]:3000', 'http://localhost:3000'];
|
];
|
||||||
|
|
||||||
const disallowedHttpAddresses = [
|
const nonHttpAddresses = [
|
||||||
'http://example.com',
|
'ftp://example.com',
|
||||||
'http://localhost.com'
|
'file://localhost',
|
||||||
];
|
'ws://example.com',
|
||||||
|
'wss://localhost',
|
||||||
const nonHttpAddresses = [
|
'https://example.com/test',
|
||||||
'ftp://example.com',
|
'https://localhost.com'
|
||||||
'file://localhost',
|
];
|
||||||
'ws://example.com',
|
|
||||||
'wss://localhost',
|
allowedHttpAddresses.forEach(address => {
|
||||||
'https://example.com/test',
|
expect(httpValidator(address)).toBeNull();
|
||||||
'https://localhost.com'
|
});
|
||||||
];
|
|
||||||
|
disallowedHttpAddresses.forEach(address => {
|
||||||
allowedHttpAddresses.forEach(address => {
|
expect(httpValidator(address)).not.toBeNull();
|
||||||
expect(httpValidator(address)).toBeNull();
|
});
|
||||||
});
|
|
||||||
|
nonHttpAddresses.forEach(address => {
|
||||||
disallowedHttpAddresses.forEach(address => {
|
expect(httpValidator(address)).toBeNull();
|
||||||
expect(httpValidator(address)).not.toBeNull();
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
nonHttpAddresses.forEach(address => {
|
test('pathValidator', () => {
|
||||||
expect(httpValidator(address)).toBeNull();
|
const rootAddresses = [
|
||||||
});
|
'http://example.com/',
|
||||||
});
|
'http://example.com',
|
||||||
|
'https://example.com/',
|
||||||
test('pathValidator', () => {
|
'https://localhost.com'
|
||||||
const rootAddresses = [
|
];
|
||||||
'http://example.com/',
|
|
||||||
'http://example.com',
|
const nonRootAddresses = [
|
||||||
'https://example.com/',
|
'http://example.com/path',
|
||||||
'https://localhost.com'
|
'http://example.com/path/',
|
||||||
];
|
'https://example.com/path',
|
||||||
|
'https://example.com/path/'
|
||||||
const nonRootAddresses = [
|
];
|
||||||
'http://example.com/path',
|
|
||||||
'http://example.com/path/',
|
rootAddresses.forEach(address => {
|
||||||
'https://example.com/path',
|
expect(pathValidator(address)).toBeNull();
|
||||||
'https://example.com/path/'
|
});
|
||||||
];
|
|
||||||
|
nonRootAddresses.forEach(address => {
|
||||||
rootAddresses.forEach(address => {
|
expect(pathValidator(address)).not.toBeNull();
|
||||||
expect(pathValidator(address)).toBeNull();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
nonRootAddresses.forEach(address => {
|
|
||||||
expect(pathValidator(address)).not.toBeNull();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import { render, fireEvent, screen } from '@testing-library/react';
|
import { render, fireEvent, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@@ -20,69 +21,71 @@ const defaultTestProps: StrictSolutionFormProps = {
|
|||||||
submit: () => undefined
|
submit: () => undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should render', () => {
|
describe('<StrictSolutionForm />', () => {
|
||||||
render(<StrictSolutionForm {...defaultTestProps} />);
|
test('should render', () => {
|
||||||
|
render(<StrictSolutionForm {...defaultTestProps} />);
|
||||||
|
|
||||||
const websiteInput = screen.getByLabelText(/WebSite label/);
|
const websiteInput = screen.getByLabelText(/WebSite label/);
|
||||||
expect(websiteInput).toBeRequired();
|
expect(websiteInput).toBeRequired();
|
||||||
expect(websiteInput).toHaveAttribute('type', 'url');
|
expect(websiteInput).toHaveAttribute('type', 'url');
|
||||||
|
|
||||||
const button = screen.getByText(/submit/i);
|
const button = screen.getByText(/submit/i);
|
||||||
expect(button).toHaveAttribute('type', 'submit');
|
expect(button).toHaveAttribute('type', 'submit');
|
||||||
expect(button).toHaveAttribute('aria-disabled', 'true');
|
expect(button).toHaveAttribute('aria-disabled', 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render with default values', () => {
|
test('should render with default values', () => {
|
||||||
const websiteValue = 'http://mysite.com';
|
const websiteValue = 'http://mysite.com';
|
||||||
const nameValue = 'John';
|
const nameValue = 'John';
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<StrictSolutionForm
|
<StrictSolutionForm
|
||||||
{...defaultTestProps}
|
{...defaultTestProps}
|
||||||
enableSubmit={true}
|
enableSubmit={true}
|
||||||
initialValues={{ name: nameValue, website: websiteValue }}
|
initialValues={{ name: nameValue, website: websiteValue }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const nameInput = screen.getByLabelText(/name Label/);
|
const nameInput = screen.getByLabelText(/name Label/);
|
||||||
expect(nameInput).toHaveValue(nameValue);
|
expect(nameInput).toHaveValue(nameValue);
|
||||||
|
|
||||||
const websiteInput = screen.getByLabelText(/WebSite label/);
|
const websiteInput = screen.getByLabelText(/WebSite label/);
|
||||||
expect(websiteInput).toHaveValue(websiteValue);
|
expect(websiteInput).toHaveValue(websiteValue);
|
||||||
|
|
||||||
const button = screen.getByText(/submit/i);
|
const button = screen.getByText(/submit/i);
|
||||||
expect(button).toBeEnabled();
|
expect(button).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should submit', () => {
|
test('should submit', () => {
|
||||||
const submit = jest.fn();
|
const submit = vi.fn();
|
||||||
const props = {
|
const props = {
|
||||||
...defaultTestProps,
|
...defaultTestProps,
|
||||||
submit
|
submit
|
||||||
};
|
};
|
||||||
const websiteValue = 'http://mysite.com';
|
const websiteValue = 'http://mysite.com';
|
||||||
|
|
||||||
render(<StrictSolutionForm {...props} />);
|
render(<StrictSolutionForm {...props} />);
|
||||||
|
|
||||||
const websiteInput = screen.getByLabelText(/WebSite label/);
|
const websiteInput = screen.getByLabelText(/WebSite label/);
|
||||||
fireEvent.change(websiteInput, { target: { value: websiteValue } });
|
fireEvent.change(websiteInput, { target: { value: websiteValue } });
|
||||||
expect(websiteInput).toHaveValue(websiteValue);
|
expect(websiteInput).toHaveValue(websiteValue);
|
||||||
|
|
||||||
const button = screen.getByText(/submit/i);
|
const button = screen.getByText(/submit/i);
|
||||||
expect(button).toBeEnabled();
|
expect(button).toBeEnabled();
|
||||||
|
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
expect(submit).toHaveBeenCalledTimes(1);
|
expect(submit).toHaveBeenCalledTimes(1);
|
||||||
expect((submit.mock.calls[0] as unknown[])[0]).toEqual(
|
expect((submit.mock.calls[0] as unknown[])[0]).toEqual(
|
||||||
expect.objectContaining({ values: { website: websiteValue } })
|
expect.objectContaining({ values: { website: websiteValue } })
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.change(websiteInput, { target: { value: `${websiteValue}///` } });
|
fireEvent.change(websiteInput, { target: { value: `${websiteValue}///` } });
|
||||||
expect(websiteInput).toHaveValue(`${websiteValue}///`);
|
expect(websiteInput).toHaveValue(`${websiteValue}///`);
|
||||||
|
|
||||||
fireEvent.click(button);
|
fireEvent.click(button);
|
||||||
expect(submit).toHaveBeenCalledTimes(2);
|
expect(submit).toHaveBeenCalledTimes(2);
|
||||||
expect((submit.mock.calls[1] as unknown[])[0]).toEqual(
|
expect((submit.mock.calls[1] as unknown[])[0]).toEqual(
|
||||||
expect.objectContaining({ values: { website: websiteValue } })
|
expect.objectContaining({ values: { website: websiteValue } })
|
||||||
);
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,35 +1,23 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<Loader /> matches the fullScreen render snapshot 1`] = `
|
exports[`<Loader /> > matches the fullScreen render snapshot 1`] = `
|
||||||
<div
|
<div
|
||||||
class="fcc-loader full-screen-wrapper"
|
class="fcc-loader full-screen-wrapper"
|
||||||
data-testid="fcc-loader"
|
data-testid="fcc-loader"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
class="sk-fade-in sk-spinner line-scale-pulse-out"
|
Spinner
|
||||||
>
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<Loader /> matches to the default render snapshot 1`] = `
|
exports[`<Loader /> > matches to the default render snapshot 1`] = `
|
||||||
<div
|
<div
|
||||||
class="fcc-loader "
|
class="fcc-loader "
|
||||||
data-testid="fcc-loader"
|
data-testid="fcc-loader"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
class="sk-fade-in sk-spinner line-scale-pulse-out"
|
Spinner
|
||||||
>
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
<div />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import borderColorPicker from './border-color-picker';
|
import borderColorPicker from './border-color-picker';
|
||||||
|
|
||||||
describe('Border color picker helper', () => {
|
describe('Border color picker helper', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<BlockSaveButton /> snapshot 1`] = `
|
exports[`<BlockSaveButton /> > <BlockSaveButton /> snapshot 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class=" relative inline-block mt-[0.5px] border-solid border-3 active:before:w-full active:before:h-full active:before:absolute active:before:inset-0 active:before:border-3 active:before:border-transparent active:before:bg-gray-900 active:before:opacity-20 text-center cursor-pointer no-underline block w-full bg-background-quaternary text-foreground-secondary border-foreground-secondary hover:bg-foreground-primary hover:text-background-primary hover:border-foreground-secondary dark:hover:bg-background-primary dark:hover:text-foreground-primary px-3 py-1.5 text-md"
|
class=" relative inline-block mt-[0.5px] border-solid border-3 active:before:w-full active:before:h-full active:before:absolute active:before:inset-0 active:before:border-3 active:before:border-transparent active:before:bg-gray-900 active:before:opacity-20 text-center cursor-pointer no-underline block w-full bg-background-quaternary text-foreground-secondary border-foreground-secondary hover:bg-foreground-primary hover:text-background-primary hover:border-foreground-secondary dark:hover:bg-background-primary dark:hover:text-foreground-primary px-3 py-1.5 text-md"
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import BlockSaveButton from './block-save-button';
|
import BlockSaveButton from './block-save-button';
|
||||||
|
|
||||||
test('<BlockSaveButton /> snapshot', () => {
|
describe('<BlockSaveButton />', () => {
|
||||||
const { container } = render(<BlockSaveButton />);
|
test('<BlockSaveButton /> snapshot', () => {
|
||||||
|
const { container } = render(<BlockSaveButton />);
|
||||||
|
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Button text should default to the correct translation key', () => {
|
test('Button text should default to the correct translation key', () => {
|
||||||
render(<BlockSaveButton />);
|
render(<BlockSaveButton />);
|
||||||
|
|
||||||
expect(screen.getByRole('button')).toHaveTextContent('buttons.save');
|
expect(screen.getByRole('button')).toHaveTextContent('buttons.save');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Button text should match "children"', () => {
|
test('Button text should match "children"', () => {
|
||||||
const testText = 'My Text Here';
|
const testText = 'My Text Here';
|
||||||
render(<BlockSaveButton>{testText}</BlockSaveButton>);
|
render(<BlockSaveButton>{testText}</BlockSaveButton>);
|
||||||
|
|
||||||
expect(screen.getByRole('button')).toHaveTextContent(testText);
|
expect(screen.getByRole('button')).toHaveTextContent(testText);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { create } from 'react-test-renderer';
|
import { create } from 'react-test-renderer';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<Profile/> renders correctly 1`] = `
|
exports[`<Profile/> > renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="h-[30px]"
|
class="h-[30px]"
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`should check certification page consistency 1`] = `
|
exports[`Timeline buttons test > should check certification page consistency 1`] = `
|
||||||
<div
|
<div
|
||||||
className="mx-[-15px] "
|
className="mx-[-15px] "
|
||||||
>
|
>
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
import {
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
vi,
|
||||||
|
MockInstance
|
||||||
|
} from 'vitest';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@@ -24,11 +33,10 @@ props.calendar[date1] = 1;
|
|||||||
props.calendar[date2] = 1;
|
props.calendar[date2] = 1;
|
||||||
props.calendar[date3] = 1;
|
props.calendar[date3] = 1;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
let dateNowMockFn: MockInstance;
|
||||||
let dateNowMockFn: jest.MockInstance<any, unknown[]>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dateNowMockFn = jest.spyOn(Date, 'now').mockImplementation(() => now);
|
dateNowMockFn = vi.spyOn(Date, 'now').mockImplementation(() => now);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, test, expect, beforeEach, vi } from 'vitest';
|
||||||
import { render, screen, within } from '@testing-library/react';
|
import { render, screen, within } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Stats, { calculateStreaks } from './stats';
|
import Stats, { calculateStreaks } from './stats';
|
||||||
@@ -69,10 +70,10 @@ const multipleEntriesInOneDay = {
|
|||||||
'1736946300': 1 // 2025-01-15 13:05:00 UTC
|
'1736946300': 1 // 2025-01-15 13:05:00 UTC
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
|
||||||
describe('calculateStreaks', () => {
|
describe('calculateStreaks', () => {
|
||||||
beforeEach(() => jest.setSystemTime(new Date(2025, 0, 15)));
|
beforeEach(() => vi.setSystemTime(new Date(2025, 0, 15)));
|
||||||
test('Should return 0 for the current streak if the user has not made progress today', () => {
|
test('Should return 0 for the current streak if the user has not made progress today', () => {
|
||||||
const { longestStreak, currentStreak } =
|
const { longestStreak, currentStreak } =
|
||||||
calculateStreaks(oldStreakCalendar);
|
calculateStreaks(oldStreakCalendar);
|
||||||
@@ -82,7 +83,7 @@ describe('calculateStreaks', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should calculate longest streak, regardless of how long ago they were', () => {
|
test('Should calculate longest streak, regardless of how long ago they were', () => {
|
||||||
jest.setSystemTime(new Date(2030, 0, 15));
|
vi.setSystemTime(new Date(2030, 0, 15));
|
||||||
const { longestStreak, currentStreak } =
|
const { longestStreak, currentStreak } =
|
||||||
calculateStreaks(oldStreakCalendar);
|
calculateStreaks(oldStreakCalendar);
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ describe('calculateStreaks', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should return a longest streak of 3 days when the current streak is 3 days', () => {
|
test('Should return a longest streak of 3 days when the current streak is 3 days', () => {
|
||||||
jest.setSystemTime(new Date(2025, 0, 14));
|
vi.setSystemTime(new Date(2025, 0, 14));
|
||||||
const { longestStreak, currentStreak } =
|
const { longestStreak, currentStreak } =
|
||||||
calculateStreaks(recentStreakCalendar);
|
calculateStreaks(recentStreakCalendar);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
import { useStaticQuery } from 'gatsby';
|
import { useStaticQuery } from 'gatsby';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { beforeEach, describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('../../../utils/get-words');
|
||||||
|
|
||||||
import { render, screen } from '../../../../utils/test-utils';
|
import { render, screen } from '../../../../utils/test-utils';
|
||||||
import { createStore } from '../../../redux/create-store';
|
import { createStore } from '../../../redux/create-store';
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
|
|
||||||
import { createStore } from '../../../redux/create-store';
|
|
||||||
import completedChallenges from '../../../__mocks__/completed-challenges.json';
|
|
||||||
import Timeline from './time-line';
|
|
||||||
|
|
||||||
Date.prototype.toLocaleString = jest.fn(() => 'Dec 29, 2022');
|
|
||||||
Date.prototype.toISOString = jest.fn(() => '2016-09-28T20:31:56.730Z');
|
|
||||||
|
|
||||||
jest.mock('../../../analytics');
|
|
||||||
|
|
||||||
jest.mock('gatsby', () => {
|
|
||||||
const edges = require('../../../__mocks__/edges.json');
|
|
||||||
const React = require('react');
|
|
||||||
const gatsby = jest.requireActual('gatsby');
|
|
||||||
return {
|
|
||||||
...gatsby,
|
|
||||||
useStaticQuery: jest.fn().mockReturnValue({
|
|
||||||
allChallengeNode: {
|
|
||||||
edges: edges
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
graphql: jest.fn(),
|
|
||||||
Link: jest.fn().mockImplementation(({ to, ...rest }) =>
|
|
||||||
React.createElement('a', {
|
|
||||||
...rest,
|
|
||||||
href: to,
|
|
||||||
gatsby: 'true'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check certification page consistency', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Provider store={createStore()}>
|
|
||||||
<Timeline
|
|
||||||
completedMap={completedChallenges}
|
|
||||||
username='CeritifedUser'
|
|
||||||
onPress={() => {}}
|
|
||||||
/>
|
|
||||||
</Provider>
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
|
import { createStore } from '../../../redux/create-store';
|
||||||
|
import completedChallenges from './__fixtures__/completed-challenges.json';
|
||||||
|
import Timeline from './time-line';
|
||||||
|
|
||||||
|
Date.prototype.toLocaleString = vi.fn(() => 'Dec 29, 2022');
|
||||||
|
Date.prototype.toISOString = vi.fn(() => '2016-09-28T20:31:56.730Z');
|
||||||
|
|
||||||
|
vi.mock('../../../analytics');
|
||||||
|
|
||||||
|
vi.mock('../../../utils/get-words');
|
||||||
|
|
||||||
|
vi.mock('gatsby', async () => {
|
||||||
|
const edges = require('./__fixtures__/edges.json');
|
||||||
|
const React = require('react');
|
||||||
|
const gatsby = await vi.importActual('gatsby');
|
||||||
|
return {
|
||||||
|
...gatsby,
|
||||||
|
useStaticQuery: vi.fn().mockReturnValue({
|
||||||
|
allChallengeNode: {
|
||||||
|
edges: edges
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
graphql: vi.fn(),
|
||||||
|
Link: vi.fn().mockImplementation(({ to, ...rest }) =>
|
||||||
|
React.createElement('a', {
|
||||||
|
...rest,
|
||||||
|
href: to,
|
||||||
|
gatsby: 'true'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Timeline buttons test', () => {
|
||||||
|
it('should check certification page consistency', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create(
|
||||||
|
<Provider store={createStore()}>
|
||||||
|
<Timeline
|
||||||
|
completedMap={completedChallenges}
|
||||||
|
username='CeritifedUser'
|
||||||
|
onPress={() => {}}
|
||||||
|
/>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
.toJSON();
|
||||||
|
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
@@ -5,7 +6,7 @@ import { createStore } from 'redux';
|
|||||||
import { UserThemes } from '../../redux/types';
|
import { UserThemes } from '../../redux/types';
|
||||||
import Profile from './profile';
|
import Profile from './profile';
|
||||||
|
|
||||||
jest.mock('../../analytics');
|
vi.mock('../../analytics');
|
||||||
//workaround to avoid some strange gatsby error:
|
//workaround to avoid some strange gatsby error:
|
||||||
window.___loader = { enqueue: () => {}, hovering: () => {} };
|
window.___loader = { enqueue: () => {}, hovering: () => {} };
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ShallowRenderer from 'react-test-renderer/shallow';
|
import ShallowRenderer from 'react-test-renderer/shallow';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
import { SearchBar } from './search-bar';
|
import { SearchBar } from './search-bar';
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ describe('<SearchBar />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const searchBarProps = {
|
const searchBarProps = {
|
||||||
toggleSearchDropdown: jest.fn(),
|
toggleSearchDropdown: vi.fn(),
|
||||||
toggleSearchFocused: jest.fn(),
|
toggleSearchFocused: vi.fn(),
|
||||||
updateSearchQuery: jest.fn()
|
updateSearchQuery: vi.fn()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as Gatsby from 'gatsby';
|
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||||
|
|
||||||
import SEO from './index';
|
import SEO from './index';
|
||||||
|
|
||||||
const useStaticQuery = jest.spyOn(Gatsby, `useStaticQuery`);
|
|
||||||
const mockUseStaticQuery = {
|
const mockUseStaticQuery = {
|
||||||
site: {
|
site: {
|
||||||
siteMetadata: {
|
siteMetadata: {
|
||||||
title: 'freeCodeCamp',
|
title: 'freeCodeCamp'
|
||||||
siteUrl: 'freeCodeCamp.org'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('react-i18next', () => ({
|
vi.mock('gatsby', () => ({
|
||||||
|
useStaticQuery: vi.fn(() => mockUseStaticQuery),
|
||||||
|
graphql: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('react-i18next', () => ({
|
||||||
useTranslation: () => {
|
useTranslation: () => {
|
||||||
return {
|
return {
|
||||||
t: (str: string) => ({
|
t: (str: string) => ({
|
||||||
@@ -27,12 +30,8 @@ jest.mock('react-i18next', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe('<SEO />', () => {
|
describe('<SEO />', () => {
|
||||||
beforeEach(() => {
|
|
||||||
useStaticQuery.mockImplementation(() => mockUseStaticQuery);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders', () => {
|
it('renders', () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<Honesty /> <Honesty /> snapshot when isHonest is false: Honesty 1`] = `
|
exports[`<Honesty /> > <Honesty /> snapshot when isHonest is false > Honesty 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<section
|
<section
|
||||||
id="honesty-policy"
|
id="honesty-policy"
|
||||||
@@ -67,7 +67,7 @@ exports[`<Honesty /> <Honesty /> snapshot when isHonest is false: Honesty 1`] =
|
|||||||
</DocumentFragment>
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`<Honesty /> <Honesty /> snapshot when isHonest is true: HonestyAccepted 1`] = `
|
exports[`<Honesty /> > <Honesty /> snapshot when isHonest is true > HonestyAccepted 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<section
|
<section
|
||||||
id="honesty-policy"
|
id="honesty-policy"
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('../../utils/get-words');
|
||||||
|
|
||||||
import { createStore } from '../../redux/create-store';
|
import { createStore } from '../../redux/create-store';
|
||||||
import { Ext } from '../../redux/prop-types';
|
import { Ext } from '../../redux/prop-types';
|
||||||
import { verifyCert } from '../../redux/settings/actions';
|
import { verifyCert } from '../../redux/settings/actions';
|
||||||
@@ -8,7 +12,7 @@ import { createFlashMessage } from '../Flash/redux';
|
|||||||
|
|
||||||
import CertificationSettings from './certification';
|
import CertificationSettings from './certification';
|
||||||
|
|
||||||
jest.mock('../../analytics');
|
vi.mock('../../analytics');
|
||||||
|
|
||||||
function renderWithRedux(ui: JSX.Element) {
|
function renderWithRedux(ui: JSX.Element) {
|
||||||
return render(<Provider store={createStore()}>{ui}</Provider>);
|
return render(<Provider store={createStore()}>{ui}</Provider>);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, fireEvent, screen } from '@testing-library/react';
|
import { render, fireEvent, screen } from '@testing-library/react';
|
||||||
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
import Honesty from './honesty';
|
import Honesty from './honesty';
|
||||||
|
|
||||||
describe('<Honesty />', () => {
|
describe('<Honesty />', () => {
|
||||||
const updateIsHonestMock = jest.fn();
|
const updateIsHonestMock = vi.fn();
|
||||||
|
|
||||||
test('<Honesty /> snapshot when isHonest is false', () => {
|
test('<Honesty /> snapshot when isHonest is false', () => {
|
||||||
const { asFragment } = render(
|
const { asFragment } = render(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
import { ShareTemplate } from './share-template';
|
import { ShareTemplate } from './share-template';
|
||||||
|
|
||||||
const redirectURL = 'string';
|
const redirectURL = 'string';
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
import { renderHook } from '@testing-library/react-hooks';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
import {
|
import {
|
||||||
hastag,
|
hastag,
|
||||||
nextLine,
|
nextLine,
|
||||||
@@ -9,29 +11,37 @@ import {
|
|||||||
threadsData
|
threadsData
|
||||||
} from './use-share';
|
} from './use-share';
|
||||||
|
|
||||||
test('useShare testing', () => {
|
describe('useShare', () => {
|
||||||
const superBlock = 'testSuperBlock';
|
test('useShare hook returns correct social media URLs', () => {
|
||||||
const block = 'testBlock';
|
const superBlock = 'testSuperBlock';
|
||||||
const { t } = useTranslation();
|
const block = 'testBlock';
|
||||||
|
|
||||||
const redirectURL = useShare({
|
const { result: translationResult } = renderHook(() => useTranslation());
|
||||||
superBlock: superBlock,
|
const { t } = translationResult.current;
|
||||||
block: block
|
|
||||||
|
// Test useShare hook
|
||||||
|
const { result: shareResult } = renderHook(() =>
|
||||||
|
useShare({
|
||||||
|
superBlock,
|
||||||
|
block
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const freecodecampLearnDomain = 'www.freecodecamp.org/learn';
|
||||||
|
const i18nSupportedBlock = t(`intro:${superBlock}.blocks.${block}.title`);
|
||||||
|
const tweetMessage = `I${space}have${space}completed${space}${i18nSupportedBlock}${space}${hastag}freecodecamp`;
|
||||||
|
const redirectFreeCodeCampLearnURL = `https://${freecodecampLearnDomain}/${superBlock}/${hastag}${block}`;
|
||||||
|
|
||||||
|
expect(shareResult.current.xUrl).toBe(
|
||||||
|
`https://${twitterData.domain}/${twitterData.action}?original_referer=${twitterData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(shareResult.current.blueSkyUrl).toBe(
|
||||||
|
`https://${blueSkyData.domain}/${blueSkyData.action}?original_referer=${blueSkyData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(shareResult.current.threadsURL).toBe(
|
||||||
|
`https://${threadsData.domain}/${threadsData.action}?original_referer=${threadsData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const freecodecampLearnDomain = 'www.freecodecamp.org/learn';
|
|
||||||
const i18nSupportedBlock = t(`intro:${superBlock}.blocks.${block}.title`);
|
|
||||||
const tweetMessage = `I${space}have${space}completed${space}${i18nSupportedBlock}${space}%23freecodecamp`;
|
|
||||||
const redirectFreeCodeCampLearnURL = `https://${freecodecampLearnDomain}/${superBlock}/${hastag}${block}`;
|
|
||||||
expect(redirectURL.xUrl).toBe(
|
|
||||||
`https://${twitterData.domain}/${twitterData.action}?original_referer=${twitterData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(redirectURL.blueSkyUrl).toBe(
|
|
||||||
`https://${blueSkyData.domain}/${blueSkyData.action}?original_referer=${blueSkyData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(redirectURL.threadsURL).toBe(
|
|
||||||
`https://${threadsData.domain}/${threadsData.action}?original_referer=${threadsData.developerDomainURL}&text=${tweetMessage}${nextLine}&url=${redirectFreeCodeCampLearnURL}`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
import { describe, it, expect, beforeAll, afterEach, vi } from 'vitest';
|
||||||
import StagingWarningModal from '.';
|
import StagingWarningModal from '.';
|
||||||
|
|
||||||
describe('StagingWarningModal', () => {
|
describe('StagingWarningModal', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
// The Modal component uses `ResizeObserver` under the hood.
|
// The Modal component uses `ResizeObserver` under the hood.
|
||||||
@@ -9,16 +11,16 @@ describe('StagingWarningModal', () => {
|
|||||||
// Ref: https://github.com/jsdom/jsdom/issues/3368
|
// Ref: https://github.com/jsdom/jsdom/issues/3368
|
||||||
Object.defineProperty(window, 'ResizeObserver', {
|
Object.defineProperty(window, 'ResizeObserver', {
|
||||||
writable: true,
|
writable: true,
|
||||||
value: jest.fn(() => ({
|
value: vi.fn(() => ({
|
||||||
observe: jest.fn(),
|
observe: vi.fn(),
|
||||||
unobserve: jest.fn(),
|
unobserve: vi.fn(),
|
||||||
disconnect: jest.fn()
|
disconnect: vi.fn()
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the modal successfully', () => {
|
it('renders the modal successfully', () => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { navigate, withPrefix } from 'gatsby';
|
import { navigate, withPrefix } from 'gatsby';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
import Challenges from './challenges';
|
import Challenges from './challenges';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
import { expectSaga } from 'redux-saga-test-plan';
|
import { expectSaga } from 'redux-saga-test-plan';
|
||||||
|
import { describe, it, vi } from 'vitest';
|
||||||
import {
|
import {
|
||||||
postChargeStripe,
|
postChargeStripe,
|
||||||
postChargeStripeCard,
|
postChargeStripeCard,
|
||||||
@@ -18,11 +20,11 @@ import {
|
|||||||
updateCardError
|
updateCardError
|
||||||
} from './actions';
|
} from './actions';
|
||||||
|
|
||||||
jest.mock('../utils/ajax');
|
vi.mock('../utils/ajax');
|
||||||
jest.mock('../analytics/call-ga');
|
vi.mock('../analytics/call-ga');
|
||||||
jest.mock('../utils/stripe', () => ({
|
vi.mock('../utils/stripe', () => ({
|
||||||
stripe: Promise.resolve({
|
stripe: Promise.resolve({
|
||||||
redirectToCheckout: jest.fn()
|
redirectToCheckout: vi.fn()
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ const postChargeDataMock = {
|
|||||||
paymentContext: 'donate page',
|
paymentContext: 'donate page',
|
||||||
amount: '500',
|
amount: '500',
|
||||||
duration: 'month',
|
duration: 'month',
|
||||||
handleAuthentication: jest.fn(),
|
handleAuthentication: vi.fn(),
|
||||||
paymentMethodId: '123456'
|
paymentMethodId: '123456'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { ActionsObservable, StateObservable } from 'redux-observable';
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { actionTypes } from './action-types';
|
import { actionTypes } from './action-types';
|
||||||
import failedUpdatesEpic from './failed-updates-epic';
|
import failedUpdatesEpic from './failed-updates-epic';
|
||||||
|
|
||||||
jest.mock('../analytics');
|
vi.mock('../analytics');
|
||||||
|
|
||||||
const key = 'fcc-failed-updates';
|
const key = 'fcc-failed-updates';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import type {
|
import type {
|
||||||
ChallengeFile,
|
ChallengeFile,
|
||||||
SavedChallengeFile
|
SavedChallengeFile
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<ChallengeTitle/> renders correctly 1`] = `
|
exports[`<ChallengeTitle/> > renders correctly 1`] = `
|
||||||
<div
|
<div
|
||||||
className="challenge-title-wrap"
|
className="challenge-title-wrap"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
import ChallengeTitle from './challenge-title';
|
import ChallengeTitle from './challenge-title';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
import ChallengeTranscript from './challenge-transcript';
|
import ChallengeTranscript from './challenge-transcript';
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { runSaga } from 'redux-saga';
|
import { runSaga } from 'redux-saga';
|
||||||
|
import { describe, test, it, expect, beforeEach, vi, Mock } from 'vitest';
|
||||||
import { render } from '../../../../utils/test-utils';
|
import { render } from '../../../../utils/test-utils';
|
||||||
|
|
||||||
import { getCompletedPercentage } from '../../../utils/get-completion-percentage';
|
import { getCompletedPercentage } from '../../../utils/get-completion-percentage';
|
||||||
@@ -15,21 +16,21 @@ import {
|
|||||||
} from '../redux/selectors';
|
} from '../redux/selectors';
|
||||||
import { buildChallenge, getTestRunner } from '../utils/build';
|
import { buildChallenge, getTestRunner } from '../utils/build';
|
||||||
import CompletionModal, { combineFileData } from './completion-modal';
|
import CompletionModal, { combineFileData } from './completion-modal';
|
||||||
jest.mock('../../../analytics');
|
vi.mock('../../../analytics');
|
||||||
jest.mock('../../../utils/fire-confetti');
|
vi.mock('../../../utils/fire-confetti');
|
||||||
jest.mock('../../../components/Progress');
|
vi.mock('../../../components/Progress');
|
||||||
jest.mock('../redux/selectors');
|
vi.mock('../redux/selectors');
|
||||||
jest.mock('../utils/build');
|
vi.mock('../utils/build');
|
||||||
const mockFireConfetti = fireConfetti as jest.Mock;
|
vi.mock('../../../utils/get-words');
|
||||||
const mockTestRunner = jest.fn().mockReturnValue({ pass: true });
|
const mockFireConfetti = fireConfetti as Mock;
|
||||||
const mockBuildEnabledSelector = isBuildEnabledSelector as jest.Mock;
|
const mockTestRunner = vi.fn().mockReturnValue({ pass: true });
|
||||||
const mockChallengeTestsSelector = challengeTestsSelector as jest.Mock;
|
const mockBuildEnabledSelector = isBuildEnabledSelector as Mock;
|
||||||
const mockChallengeMetaSelector = challengeMetaSelector as jest.Mock;
|
const mockChallengeTestsSelector = challengeTestsSelector as Mock;
|
||||||
const mockChallengeDataSelector = challengeDataSelector as jest.Mock;
|
const mockChallengeMetaSelector = challengeMetaSelector as Mock;
|
||||||
const mockIsBlockNewlyCompletedSelector =
|
const mockChallengeDataSelector = challengeDataSelector as Mock;
|
||||||
isBlockNewlyCompletedSelector as jest.Mock;
|
const mockIsBlockNewlyCompletedSelector = isBlockNewlyCompletedSelector as Mock;
|
||||||
const mockBuildChallenge = buildChallenge as jest.Mock;
|
const mockBuildChallenge = buildChallenge as Mock;
|
||||||
const mockGetTestRunner = getTestRunner as jest.Mock;
|
const mockGetTestRunner = getTestRunner as Mock;
|
||||||
mockBuildEnabledSelector.mockReturnValue(true);
|
mockBuildEnabledSelector.mockReturnValue(true);
|
||||||
mockChallengeTestsSelector.mockReturnValue([
|
mockChallengeTestsSelector.mockReturnValue([
|
||||||
{ text: 'Test 1', testString: 'mock test code' }
|
{ text: 'Test 1', testString: 'mock test code' }
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import i18n from '../../../../i18n/config-for-tests';
|
import i18n from '../../../../i18n/config-for-tests';
|
||||||
import { generateSearchLink } from './help-modal';
|
import { generateSearchLink } from './help-modal';
|
||||||
|
|
||||||
|
vi.unmock('react-i18next');
|
||||||
|
|
||||||
describe('generateSearchLink', () => {
|
describe('generateSearchLink', () => {
|
||||||
it("should return a link with search query containing block name and challenge title if the title includes 'step'", async () => {
|
it("should return a link with search query containing block name and challenge title if the title includes 'step'", async () => {
|
||||||
await i18n.reloadResources('en', 'intro');
|
await i18n.reloadResources('en', 'intro');
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { parseBlanks } from './parse-blanks';
|
import { parseBlanks } from './parse-blanks';
|
||||||
|
|
||||||
describe('parseBlanks', () => {
|
describe('parseBlanks', () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { TestScheduler } from 'rxjs/testing';
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import completionEpic from './completion-epic';
|
import completionEpic from './completion-epic';
|
||||||
import { submitChallenge, submitChallengeComplete } from './actions';
|
import { submitChallenge, submitChallengeComplete } from './actions';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { transformEditorLink } from '../utils';
|
import { transformEditorLink } from '../utils';
|
||||||
import { insertEditableRegions } from './create-question-epic';
|
import { insertEditableRegions } from './create-question-epic';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import { expectSaga } from 'redux-saga-test-plan';
|
import { expectSaga } from 'redux-saga-test-plan';
|
||||||
|
import { describe, it, vi } from 'vitest';
|
||||||
|
|
||||||
jest.mock('redux-saga/effects', () => ({
|
vi.mock('redux-saga/effects', async importOriginal => {
|
||||||
...jest.requireActual('redux-saga/effects'),
|
const actual = await importOriginal();
|
||||||
delay: jest.fn()
|
return {
|
||||||
}));
|
...actual,
|
||||||
|
delay: vi.fn()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
challenge: { isBuildEnabled: true, isExecuting: false, challengeMeta: {} }
|
challenge: { isBuildEnabled: true, isExecuting: false, challengeMeta: {} }
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import envData from '../../../../config/env.json';
|
import envData from '../../../../config/env.json';
|
||||||
import { getGuideUrl } from './index';
|
import { getGuideUrl } from './index';
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* @jest-environment node
|
* @vitest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { it, expect, afterEach, vi } from 'vitest';
|
||||||
import { WorkerExecutor } from './worker-executor';
|
import { WorkerExecutor } from './worker-executor';
|
||||||
|
|
||||||
function mockWorker({ init, postMessage, terminate } = {}) {
|
function mockWorker({ init, postMessage, terminate } = {}) {
|
||||||
global.Worker = jest.fn(function () {
|
global.Worker = vi.fn(function () {
|
||||||
setImmediate(
|
setImmediate(
|
||||||
(init && init(this)) ||
|
(init && init(this)) ||
|
||||||
(() =>
|
(() =>
|
||||||
@@ -29,7 +30,7 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Worker executor should successfully execute one task', async () => {
|
it('Worker executor should successfully execute one task', async () => {
|
||||||
const terminateHandler = jest.fn();
|
const terminateHandler = vi.fn();
|
||||||
mockWorker({ terminate: terminateHandler });
|
mockWorker({ terminate: terminateHandler });
|
||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
expect(testWorker).not.toBeUndefined();
|
expect(testWorker).not.toBeUndefined();
|
||||||
@@ -37,9 +38,9 @@ it('Worker executor should successfully execute one task', async () => {
|
|||||||
const task = testWorker.execute('test');
|
const task = testWorker.execute('test');
|
||||||
expect(task).not.toBeUndefined();
|
expect(task).not.toBeUndefined();
|
||||||
expect(task.done).not.toBeUndefined();
|
expect(task.done).not.toBeUndefined();
|
||||||
const handler = jest.fn();
|
const handler = vi.fn();
|
||||||
task.on('done', handler);
|
task.on('done', handler);
|
||||||
const errorHandler = jest.fn();
|
const errorHandler = vi.fn();
|
||||||
task.on('error', errorHandler);
|
task.on('error', errorHandler);
|
||||||
|
|
||||||
await expect(task.done).resolves.toBe('test processed');
|
await expect(task.done).resolves.toBe('test processed');
|
||||||
@@ -55,20 +56,20 @@ it('Worker executor should successfully execute one task', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Worker executor should successfully execute two tasks in parallel', async () => {
|
it('Worker executor should successfully execute two tasks in parallel', async () => {
|
||||||
const terminateHandler = jest.fn();
|
const terminateHandler = vi.fn();
|
||||||
mockWorker({ terminate: terminateHandler });
|
mockWorker({ terminate: terminateHandler });
|
||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
|
|
||||||
const task1 = testWorker.execute('test1');
|
const task1 = testWorker.execute('test1');
|
||||||
const handler1 = jest.fn();
|
const handler1 = vi.fn();
|
||||||
task1.on('done', handler1);
|
task1.on('done', handler1);
|
||||||
const errorHandler1 = jest.fn();
|
const errorHandler1 = vi.fn();
|
||||||
task1.on('error', errorHandler1);
|
task1.on('error', errorHandler1);
|
||||||
|
|
||||||
const task2 = testWorker.execute('test2');
|
const task2 = testWorker.execute('test2');
|
||||||
const handler2 = jest.fn();
|
const handler2 = vi.fn();
|
||||||
task2.on('done', handler2);
|
task2.on('done', handler2);
|
||||||
const errorHandler2 = jest.fn();
|
const errorHandler2 = vi.fn();
|
||||||
task2.on('error', errorHandler2);
|
task2.on('error', errorHandler2);
|
||||||
|
|
||||||
await expect(Promise.all([task1.done, task2.done])).resolves.toEqual([
|
await expect(Promise.all([task1.done, task2.done])).resolves.toEqual([
|
||||||
@@ -103,7 +104,7 @@ it('Worker executor should successfully execute 3 tasks in parallel and use two
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Worker executor should successfully execute 3 tasks, use 3 workers and terminate each worker', async () => {
|
it('Worker executor should successfully execute 3 tasks, use 3 workers and terminate each worker', async () => {
|
||||||
const terminateHandler = jest.fn();
|
const terminateHandler = vi.fn();
|
||||||
mockWorker({ terminate: terminateHandler });
|
mockWorker({ terminate: terminateHandler });
|
||||||
const testWorker = new WorkerExecutor('test', { terminateWorker: true });
|
const testWorker = new WorkerExecutor('test', { terminateWorker: true });
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ it('Worker executor should reject task', async () => {
|
|||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
|
|
||||||
const task = testWorker.execute('test');
|
const task = testWorker.execute('test');
|
||||||
const errorHandler = jest.fn();
|
const errorHandler = vi.fn();
|
||||||
task.on('error', errorHandler);
|
task.on('error', errorHandler);
|
||||||
await expect(task.done).rejects.toBe(error.message);
|
await expect(task.done).rejects.toBe(error.message);
|
||||||
|
|
||||||
@@ -184,11 +185,11 @@ it('Worker executor should emit LOG events', async () => {
|
|||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
|
|
||||||
const task = testWorker.execute('test');
|
const task = testWorker.execute('test');
|
||||||
const handler = jest.fn();
|
const handler = vi.fn();
|
||||||
task.on('done', handler);
|
task.on('done', handler);
|
||||||
const errorHandler = jest.fn();
|
const errorHandler = vi.fn();
|
||||||
task.on('error', errorHandler);
|
task.on('error', errorHandler);
|
||||||
const logHandler = jest.fn();
|
const logHandler = vi.fn();
|
||||||
task.on('LOG', logHandler);
|
task.on('LOG', logHandler);
|
||||||
|
|
||||||
await expect(task.done).resolves.toBe('test processed');
|
await expect(task.done).resolves.toBe('test processed');
|
||||||
@@ -204,7 +205,7 @@ it('Worker executor should emit LOG events', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Worker executor should reject task on timeout', async () => {
|
it('Worker executor should reject task on timeout', async () => {
|
||||||
const terminateHandler = jest.fn();
|
const terminateHandler = vi.fn();
|
||||||
mockWorker({
|
mockWorker({
|
||||||
postMessage: () => {},
|
postMessage: () => {},
|
||||||
terminate: terminateHandler
|
terminate: terminateHandler
|
||||||
@@ -212,7 +213,7 @@ it('Worker executor should reject task on timeout', async () => {
|
|||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
|
|
||||||
const task = testWorker.execute('test', 0);
|
const task = testWorker.execute('test', 0);
|
||||||
const errorHandler = jest.fn();
|
const errorHandler = vi.fn();
|
||||||
task.on('error', errorHandler);
|
task.on('error', errorHandler);
|
||||||
await expect(task.done).rejects.toBe('timeout');
|
await expect(task.done).rejects.toBe('timeout');
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ it('Task should only emit handler once', () => {
|
|||||||
mockWorker();
|
mockWorker();
|
||||||
const testWorker = new WorkerExecutor('test');
|
const testWorker = new WorkerExecutor('test');
|
||||||
const task = testWorker.execute('test');
|
const task = testWorker.execute('test');
|
||||||
const handler = jest.fn();
|
const handler = vi.fn();
|
||||||
task.once('testOnce', handler);
|
task.once('testOnce', handler);
|
||||||
|
|
||||||
task.emit('testOnce', handler);
|
task.emit('testOnce', handler);
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`<BlockIntros /> matches snapshot 1`] = `
|
exports[`<BlockIntros /> > matches snapshot 1`] = `
|
||||||
<div
|
<div
|
||||||
className="block-description"
|
className="block-description"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import BlockIntros from './block-intros';
|
import BlockIntros from './block-intros';
|
||||||
|
|
||||||
const arrString = ['first paragraph', 'second paragraph'];
|
const arrString = ['first paragraph', 'second paragraph'];
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { Provider } from 'react-redux';
|
import { describe, it, expect, afterEach, vi, Mock } from 'vitest';
|
||||||
|
import type { TFunction } from 'i18next';
|
||||||
import { SuperBlocks } from '../../../../../shared/config/curriculum';
|
import { SuperBlocks } from '../../../../../shared/config/curriculum';
|
||||||
import { createStore } from '../../../redux/create-store';
|
|
||||||
import {
|
import {
|
||||||
ChallengeFiles,
|
ChallengeFiles,
|
||||||
PrerequisiteChallenge,
|
PrerequisiteChallenge,
|
||||||
@@ -14,18 +14,13 @@ import {
|
|||||||
} from '../../../redux/prop-types';
|
} from '../../../redux/prop-types';
|
||||||
import { isAuditedSuperBlock } from '../../../../../shared/utils/is-audited';
|
import { isAuditedSuperBlock } from '../../../../../shared/utils/is-audited';
|
||||||
import { BlockLayouts, BlockTypes } from '../../../../../shared/config/blocks';
|
import { BlockLayouts, BlockTypes } from '../../../../../shared/config/blocks';
|
||||||
import Block from './block';
|
import { Block } from './block';
|
||||||
|
|
||||||
jest.mock('../../../../../shared/utils/is-audited', () => ({
|
vi.mock('../../../../../shared/utils/is-audited', () => ({
|
||||||
isAuditedSuperBlock: jest.fn().mockReturnValueOnce(true)
|
isAuditedSuperBlock: vi.fn().mockReturnValueOnce(true)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../redux', () => ({
|
vi.mock('../../../utils/get-words');
|
||||||
makeExpandedBlockSelector: jest.fn(() => jest.fn(() => true)),
|
|
||||||
completedChallengesSelector: jest.fn(() => [
|
|
||||||
{ id: 'mockId', title: 'mockTitle' }
|
|
||||||
])
|
|
||||||
}));
|
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
block: 'test-block',
|
block: 'test-block',
|
||||||
@@ -91,46 +86,34 @@ const defaultProps = {
|
|||||||
],
|
],
|
||||||
completedChallengeIds: ['testchallengeIds'],
|
completedChallengeIds: ['testchallengeIds'],
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
t: jest.fn((key: string) => [key]),
|
t: vi.fn((key: string) => [key]) as unknown as TFunction,
|
||||||
superBlock: SuperBlocks.FullStackDeveloper,
|
superBlock: SuperBlocks.FullStackDeveloper,
|
||||||
toggleBlock: jest.fn()
|
toggleBlock: vi.fn()
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('<Block />', () => {
|
describe('<Block />', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('The "Help us translate" badge does not appear on any English blocks', () => {
|
it('The "Help us translate" badge does not appear on any English blocks', () => {
|
||||||
render(
|
render(<Block {...defaultProps} />);
|
||||||
<Provider store={createStore()}>
|
|
||||||
<Block {...defaultProps} />
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
screen.queryByText(/misc.translation-pending/)
|
screen.queryByText(/misc.translation-pending/)
|
||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`The "Help us translate" badge does not appear on any i18n blocks when the superblock is audited`, () => {
|
it(`The "Help us translate" badge does not appear on any i18n blocks when the superblock is audited`, () => {
|
||||||
(isAuditedSuperBlock as jest.Mock).mockReturnValue(true);
|
(isAuditedSuperBlock as Mock).mockReturnValue(true);
|
||||||
render(
|
render(<Block {...defaultProps} />);
|
||||||
<Provider store={createStore()}>
|
|
||||||
<Block {...defaultProps} />
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
screen.queryByText(/misc.translation-pending/)
|
screen.queryByText(/misc.translation-pending/)
|
||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`The "Help us translate" badge does appear on i18n blocks when the superblock is not audited`, () => {
|
it(`The "Help us translate" badge does appear on i18n blocks when the superblock is not audited`, () => {
|
||||||
(isAuditedSuperBlock as jest.Mock).mockReturnValue(false);
|
(isAuditedSuperBlock as Mock).mockReturnValue(false);
|
||||||
render(
|
render(<Block {...defaultProps} />);
|
||||||
<Provider store={createStore()}>
|
|
||||||
<Block {...defaultProps} />
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
expect(screen.getByText(/misc.translation-pending/)).toBeInTheDocument();
|
expect(screen.getByText(/misc.translation-pending/)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ interface BlockProps {
|
|||||||
toggleBlock: typeof toggleBlock;
|
toggleBlock: typeof toggleBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Block extends Component<BlockProps> {
|
export class Block extends Component<BlockProps> {
|
||||||
static displayName: string;
|
static displayName: string;
|
||||||
constructor(props: BlockProps) {
|
constructor(props: BlockProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
|
export const randomQuote = vi.fn(() => ({
|
||||||
|
quote: 'Test quote',
|
||||||
|
author: 'Test author'
|
||||||
|
}));
|
||||||
|
export const randomCompliment = vi.fn(() => 'Great job!');
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { stringifyDonationEvents } from './analytics-strings';
|
import { stringifyDonationEvents } from './analytics-strings';
|
||||||
|
|
||||||
describe('Analytics donation strings', () => {
|
describe('Analytics donation strings', () => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { createTypes, createAsyncTypes } from './create-types';
|
import { createTypes, createAsyncTypes } from './create-types';
|
||||||
|
|
||||||
describe('Create types utility (createTypes)', () => {
|
describe('Create types utility (createTypes)', () => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { format } from './format';
|
import { format } from './format';
|
||||||
|
|
||||||
function simpleFun() {
|
function simpleFun() {
|
||||||
|
|||||||
@@ -1,30 +1,8 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { getUUID } from './growthbook-cookie';
|
import { getUUID } from './growthbook-cookie';
|
||||||
|
|
||||||
describe('getUUID', () => {
|
describe('getUUID', () => {
|
||||||
let originalCookie: string;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
global.crypto = {
|
|
||||||
...global.crypto,
|
|
||||||
randomUUID: () => '123e4567-e89b-12d3-a456-426614174000'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save original cookie
|
|
||||||
originalCookie = document.cookie;
|
|
||||||
|
|
||||||
// Clear the cookie before each test
|
|
||||||
document.cookie.split(';').forEach(c => {
|
|
||||||
document.cookie = c
|
|
||||||
.replace(/^ +/, '')
|
|
||||||
.replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
// Restore original cookie
|
|
||||||
document.cookie = originalCookie;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate a new UUID if none exists', () => {
|
it('should generate a new UUID if none exists', () => {
|
||||||
const uuid = getUUID();
|
const uuid = getUUID();
|
||||||
expect(uuid).toBeDefined();
|
expect(uuid).toBeDefined();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { isObject } from 'lodash-es';
|
import { isObject } from 'lodash-es';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { isContained } from './is-contained';
|
import { isContained } from './is-contained';
|
||||||
|
|
||||||
describe('client/src isContained', () => {
|
describe('client/src isContained', () => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { isLanding } from './path-parsers';
|
import { isLanding } from './path-parsers';
|
||||||
|
|
||||||
const pathnames = {
|
const pathnames = {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { replaceAppleQuotes } from './replace-apple-quotes';
|
import { replaceAppleQuotes } from './replace-apple-quotes';
|
||||||
|
|
||||||
describe('replaceAppleQuotes()', () => {
|
describe('replaceAppleQuotes()', () => {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
/* eslint-disable @typescript-eslint/unbound-method */
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||||
import {
|
import {
|
||||||
CURRENT_COUNT_KEY,
|
CURRENT_COUNT_KEY,
|
||||||
SAVED_COUNT_KEY,
|
SAVED_COUNT_KEY,
|
||||||
@@ -17,24 +19,24 @@ describe('Session Storage', () => {
|
|||||||
const mockStorage: Storage = {
|
const mockStorage: Storage = {
|
||||||
length: 0,
|
length: 0,
|
||||||
|
|
||||||
clear: jest.fn(() => {
|
clear: vi.fn(() => {
|
||||||
store = {};
|
store = {};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getItem: jest.fn((key: string) => {
|
getItem: vi.fn((key: string) => {
|
||||||
return store[key] || null;
|
return store[key] || null;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
key: jest.fn((index: number) => {
|
key: vi.fn((index: number) => {
|
||||||
const keys = Object.keys(store);
|
const keys = Object.keys(store);
|
||||||
return keys[index] || null;
|
return keys[index] || null;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeItem: jest.fn((key: string) => {
|
removeItem: vi.fn((key: string) => {
|
||||||
delete store[key];
|
delete store[key];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setItem: jest.fn((key: string, value: string) => {
|
setItem: vi.fn((key: string, value: string) => {
|
||||||
store[key] = value;
|
store[key] = value;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -54,16 +56,16 @@ describe('Session Storage', () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getSessionChallengeData', () => {
|
describe('getSessionChallengeData', () => {
|
||||||
describe('countSinceSave', () => {
|
describe('countSinceSave', () => {
|
||||||
it('is not included if nothing has been saved', () => {
|
test('is not included if nothing has been saved', () => {
|
||||||
expect(getSessionChallengeData()).not.toHaveProperty('countSinceSave');
|
expect(getSessionChallengeData()).not.toHaveProperty('countSinceSave');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is included if the count has been saved', () => {
|
test('is included if the count has been saved', () => {
|
||||||
sessionStorage.setItem(SAVED_COUNT_KEY, '7');
|
sessionStorage.setItem(SAVED_COUNT_KEY, '7');
|
||||||
sessionStorage.setItem(CURRENT_COUNT_KEY, '10');
|
sessionStorage.setItem(CURRENT_COUNT_KEY, '10');
|
||||||
expect(getSessionChallengeData()).toMatchObject({
|
expect(getSessionChallengeData()).toMatchObject({
|
||||||
@@ -73,13 +75,13 @@ describe('Session Storage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('currentCount', () => {
|
describe('currentCount', () => {
|
||||||
it('defaults to 0 if no challenges have been completed', () => {
|
test('defaults to 0 if no challenges have been completed', () => {
|
||||||
expect(getSessionChallengeData()).toMatchObject({
|
expect(getSessionChallengeData()).toMatchObject({
|
||||||
currentCount: 0
|
currentCount: 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the stored number if it exists', () => {
|
test('returns the stored number if test exists', () => {
|
||||||
sessionStorage.setItem(CURRENT_COUNT_KEY, '5');
|
sessionStorage.setItem(CURRENT_COUNT_KEY, '5');
|
||||||
expect(getSessionChallengeData()).toMatchObject({
|
expect(getSessionChallengeData()).toMatchObject({
|
||||||
currentCount: 5
|
currentCount: 5
|
||||||
@@ -88,13 +90,13 @@ describe('Session Storage', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('isSaved', () => {
|
describe('isSaved', () => {
|
||||||
it('is false if we haved saved the count', () => {
|
test('is false if we haved saved the count', () => {
|
||||||
expect(getSessionChallengeData()).toMatchObject({
|
expect(getSessionChallengeData()).toMatchObject({
|
||||||
isSaved: false
|
isSaved: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is true if we have saved something', () => {
|
test('is true if we have saved something', () => {
|
||||||
sessionStorage.setItem(SAVED_COUNT_KEY, '7');
|
sessionStorage.setItem(SAVED_COUNT_KEY, '7');
|
||||||
expect(getSessionChallengeData()).toMatchObject({
|
expect(getSessionChallengeData()).toMatchObject({
|
||||||
isSaved: true
|
isSaved: true
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import {
|
import {
|
||||||
bothLinks,
|
bothLinks,
|
||||||
invalidGithubLink,
|
invalidGithubLink,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { withPrefix } from 'gatsby';
|
import { withPrefix } from 'gatsby';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
import toLearnPath from './to-learn-path';
|
import toLearnPath from './to-learn-path';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
|
|
||||||
import { clientLocale } from '../config/env.json';
|
import { clientLocale } from '../config/env.json';
|
||||||
import {
|
import {
|
||||||
convertToLocalizedString,
|
convertToLocalizedString,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"i18n/**/*",
|
"i18n/**/*",
|
||||||
"plugins/**/*",
|
"plugins/**/*",
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
|
"__mocks__/**/*",
|
||||||
"utils/**/*",
|
"utils/**/*",
|
||||||
"tools/**/*",
|
"tools/**/*",
|
||||||
"config/**/*"
|
"config/**/*"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import ShallowRenderer from 'react-test-renderer/shallow';
|
import ShallowRenderer from 'react-test-renderer/shallow';
|
||||||
|
import { describe, test, expect, vi } from 'vitest';
|
||||||
|
|
||||||
import FourOhFourPage from '../../src/pages/404';
|
import FourOhFourPage from '../../src/pages/404';
|
||||||
import Certification from '../../src/pages/certification';
|
import Certification from '../../src/pages/certification';
|
||||||
@@ -9,7 +10,9 @@ import Learn from '../../src/pages/learn';
|
|||||||
import { createStore } from '../../src/redux/create-store';
|
import { createStore } from '../../src/redux/create-store';
|
||||||
import layoutSelector from './layout-selector';
|
import layoutSelector from './layout-selector';
|
||||||
|
|
||||||
jest.mock('../../src/analytics');
|
vi.mock('../../src/analytics');
|
||||||
|
|
||||||
|
vi.mock('../../src/utils/get-words');
|
||||||
|
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
|
|
||||||
@@ -60,55 +63,60 @@ const challengePageContext = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test('Challenges should have DefaultLayout and no footer', () => {
|
describe('Layout selector', () => {
|
||||||
const challengePath =
|
test('Challenges should have DefaultLayout and no footer', () => {
|
||||||
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements';
|
const challengePath =
|
||||||
const componentObj = getComponentNameAndProps(
|
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements';
|
||||||
Learn,
|
const componentObj = getComponentNameAndProps(
|
||||||
challengePath,
|
Learn,
|
||||||
challengePageContext
|
challengePath,
|
||||||
);
|
challengePageContext
|
||||||
expect(componentObj.name).toEqual('DefaultLayout');
|
);
|
||||||
expect(componentObj.props.showFooter).toEqual(false);
|
expect(componentObj.name).toEqual('DefaultLayout');
|
||||||
});
|
expect(componentObj.props.showFooter).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
test('SuperBlock path should have DefaultLayout and footer', () => {
|
test('SuperBlock path should have DefaultLayout and footer', () => {
|
||||||
const superBlockPath = '/learn/responsive-web-design/';
|
const superBlockPath = '/learn/responsive-web-design/';
|
||||||
const componentObj = getComponentNameAndProps(Learn, superBlockPath);
|
const componentObj = getComponentNameAndProps(Learn, superBlockPath);
|
||||||
expect(componentObj.name).toEqual('DefaultLayout');
|
expect(componentObj.name).toEqual('DefaultLayout');
|
||||||
expect(componentObj.props.showFooter).toEqual(true);
|
expect(componentObj.props.showFooter).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('i18n challenge path should have DefaultLayout and no footer', () => {
|
test('i18n challenge path should have DefaultLayout and no footer', () => {
|
||||||
const challengePath =
|
const challengePath =
|
||||||
'espanol/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/';
|
'espanol/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/';
|
||||||
const componentObj = getComponentNameAndProps(
|
const componentObj = getComponentNameAndProps(
|
||||||
Learn,
|
Learn,
|
||||||
challengePath,
|
challengePath,
|
||||||
challengePageContext
|
challengePageContext
|
||||||
);
|
);
|
||||||
expect(componentObj.name).toEqual('DefaultLayout');
|
expect(componentObj.name).toEqual('DefaultLayout');
|
||||||
expect(componentObj.props.showFooter).toEqual(false);
|
expect(componentObj.props.showFooter).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('i18n superBlock path should have DefaultLayout and footer', () => {
|
test('i18n superBlock path should have DefaultLayout and footer', () => {
|
||||||
const superBlockPath = '/learn/responsive-web-design/';
|
const superBlockPath = '/learn/responsive-web-design/';
|
||||||
const componentObj = getComponentNameAndProps(Learn, superBlockPath);
|
const componentObj = getComponentNameAndProps(Learn, superBlockPath);
|
||||||
expect(componentObj.name).toEqual('DefaultLayout');
|
expect(componentObj.name).toEqual('DefaultLayout');
|
||||||
expect(componentObj.props.showFooter).toEqual(true);
|
expect(componentObj.props.showFooter).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('404 page should have DefaultLayout and footer', () => {
|
test('404 page should have DefaultLayout and footer', () => {
|
||||||
const challengePath =
|
const challengePath =
|
||||||
'/espanol/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/';
|
'/espanol/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements/';
|
||||||
const componentObj = getComponentNameAndProps(FourOhFourPage, challengePath);
|
const componentObj = getComponentNameAndProps(
|
||||||
expect(componentObj.name).toEqual('DefaultLayout');
|
FourOhFourPage,
|
||||||
expect(componentObj.props.showFooter).toEqual(true);
|
challengePath
|
||||||
});
|
);
|
||||||
|
expect(componentObj.name).toEqual('DefaultLayout');
|
||||||
|
expect(componentObj.props.showFooter).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('Certification path should have CertificationLayout', () => {
|
test('Certification path should have CertificationLayout', () => {
|
||||||
const challengePath =
|
const challengePath =
|
||||||
'/certification/mot01/javascript-algorithms-and-data-structures/';
|
'/certification/mot01/javascript-algorithms-and-data-structures/';
|
||||||
const componentObj = getComponentNameAndProps(Certification, challengePath);
|
const componentObj = getComponentNameAndProps(Certification, challengePath);
|
||||||
expect(componentObj.name).toEqual('CertificationLayout');
|
expect(componentObj.name).toEqual('CertificationLayout');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
import { challengeFiles } from './__fixtures__/challenges';
|
import { challengeFiles } from './__fixtures__/challenges';
|
||||||
import { sortChallengeFiles } from './sort-challengefiles';
|
import { sortChallengeFiles } from './sort-challengefiles';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { vi, afterEach } from 'vitest';
|
||||||
|
import '@testing-library/jest-dom/vitest';
|
||||||
|
import { cleanup } from '@testing-library/react';
|
||||||
|
|
||||||
|
vi.mock('react-spinkit');
|
||||||
|
vi.mock('gatsby');
|
||||||
|
vi.mock('react-i18next');
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// Vitest doesn't automatically call cleanup. Without it the rendered
|
||||||
|
// components are never removed and so tests are not independent.
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/// <reference types="vitest/config" />
|
||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
setupFiles: 'vitest-setup.js',
|
||||||
|
exclude: 'node_modules',
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
extends: true,
|
||||||
|
test: {
|
||||||
|
include: '**/*.test.{jsx,tsx}',
|
||||||
|
name: 'react',
|
||||||
|
environment: 'jsdom'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
extends: true,
|
||||||
|
test: {
|
||||||
|
include: '**/*.test.{js,ts}',
|
||||||
|
name: 'js',
|
||||||
|
environment: 'node'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
+2
-7
@@ -6,15 +6,10 @@ module.exports = {
|
|||||||
'tools/challenge-helper-scripts/',
|
'tools/challenge-helper-scripts/',
|
||||||
'tools/challenge-parser/',
|
'tools/challenge-parser/',
|
||||||
'tools/scripts/build/',
|
'tools/scripts/build/',
|
||||||
'curriculum'
|
'curriculum',
|
||||||
|
'client'
|
||||||
],
|
],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.(jpg|jpeg|png|svg|woff|woff2)$':
|
|
||||||
'<rootDir>/client/src/__mocks__/file-mock.ts',
|
|
||||||
// Plain CSS - match css files that don't end with
|
|
||||||
// '.module.css' https://regex101.com/r/VzwrKH/4
|
|
||||||
'^(?!.*\\.module\\.css$).*\\.css$':
|
|
||||||
'<rootDir>/client/src/__mocks__/style-mock.ts',
|
|
||||||
// CSS Modules - match files that end with 'module.css'
|
// CSS Modules - match files that end with 'module.css'
|
||||||
'\\.module\\.css$': 'identity-obj-proxy',
|
'\\.module\\.css$': 'identity-obj-proxy',
|
||||||
'^lodash-es$': 'lodash'
|
'^lodash-es$': 'lodash'
|
||||||
|
|||||||
+1
-1
@@ -78,7 +78,7 @@
|
|||||||
"test:curriculum:content": "cd ./curriculum && pnpm test",
|
"test:curriculum:content": "cd ./curriculum && pnpm test",
|
||||||
"test:curriculum:tooling": "cd ./curriculum && pnpm vitest run",
|
"test:curriculum:tooling": "cd ./curriculum && pnpm vitest run",
|
||||||
"test-curriculum-full-output": "cd ./curriculum && pnpm run test:full-output",
|
"test-curriculum-full-output": "cd ./curriculum && pnpm run test:full-output",
|
||||||
"test-client": "jest client",
|
"test:client": "cd ./client && pnpm test run",
|
||||||
"test-config": "jest config",
|
"test-config": "jest config",
|
||||||
"test-tools": "jest tools",
|
"test-tools": "jest tools",
|
||||||
"test-utils": "jest utils",
|
"test-utils": "jest utils",
|
||||||
|
|||||||
Generated
+389
-134
File diff suppressed because it is too large
Load Diff
@@ -13,3 +13,9 @@ packages:
|
|||||||
- 'tools/scripts/build'
|
- 'tools/scripts/build'
|
||||||
- 'tools/scripts/seed'
|
- 'tools/scripts/seed'
|
||||||
- 'tools/scripts/seed-exams'
|
- 'tools/scripts/seed-exams'
|
||||||
|
|
||||||
|
packageExtensions:
|
||||||
|
'@testing-library/jest-dom':
|
||||||
|
peerDependencies:
|
||||||
|
jest: '*'
|
||||||
|
vitest: '*'
|
||||||
|
|||||||
Reference in New Issue
Block a user