Skip to content

test(headless): fix unit tests by changing to vitest #4449

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
747 changes: 644 additions & 103 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 0 additions & 22 deletions packages/headless-react/jest.config.mjs

This file was deleted.

9 changes: 4 additions & 5 deletions packages/headless-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"scripts": {
"build": "nx build",
"clean": "rimraf dist",
"test": "jest",
"test:watch": "jest --watch --colors --no-cache",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint .; publint",
"publish:npm": "npm run-script -w=@coveo/release npm-publish",
"publish:bump": "npm run-script -w=@coveo/release bump",
Expand All @@ -46,12 +46,11 @@
"eslint-plugin-react": "7.35.0",
"eslint-plugin-testing-library": "6.2.2",
"gts": "5.3.1",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"publint": "0.2.9",
"rimraf": "5.0.9",
"ts-jest": "29.2.3",
"typescript": "5.4.5"
"typescript": "5.4.5",
"vitest": "2.1.1"
},
"peerDependencies": {
"react": "^18",
Expand Down
45 changes: 23 additions & 22 deletions packages/headless-react/src/ssr/client-utils.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {renderHook} from '@testing-library/react';
import {vi, expect, describe, test, it} from 'vitest';
import {useSyncMemoizedStore} from './client-utils';

describe('useSyncMemoizedStore', () => {
test('should return the initial snapshot', () => {
const snapshot = {count: 0};
const unsubscribe = jest.fn();
const subscribe = jest.fn(() => unsubscribe);
const getSnapshot = jest.fn(() => snapshot);
const unsubscribe = vi.fn();
const subscribe = vi.fn(() => unsubscribe);
const getSnapshot = vi.fn(() => snapshot);

const {result} = renderHook(() =>
useSyncMemoizedStore(subscribe, getSnapshot)
Expand All @@ -17,9 +18,9 @@ describe('useSyncMemoizedStore', () => {

test('should not call getSnapshot when there is a re-render with the same getSnapshot', () => {
const snapshot = {count: 0};
const unsubscribe = jest.fn();
const subscribe = jest.fn(() => unsubscribe);
const getSnapshot = jest.fn(() => snapshot);
const unsubscribe = vi.fn();
const subscribe = vi.fn(() => unsubscribe);
const getSnapshot = vi.fn(() => snapshot);

const {rerender} = renderHook(() =>
useSyncMemoizedStore(subscribe, getSnapshot)
Expand All @@ -33,26 +34,26 @@ describe('useSyncMemoizedStore', () => {
test('should update the state when getSnapshot changes', () => {
const snapshot1 = {count: 0};
const snapshot2 = {count: 1};
const subscribe = jest.fn(() => jest.fn());
let getSnapshot = jest.fn(() => snapshot1);
const subscribe = vi.fn(() => vi.fn());
let getSnapshot = vi.fn(() => snapshot1);

const {result, rerender} = renderHook(() =>
useSyncMemoizedStore(subscribe, getSnapshot)
);

expect(result.current).toEqual(snapshot1);
getSnapshot = jest.fn(() => snapshot2);
getSnapshot = vi.fn(() => snapshot2);
rerender();
expect(result.current).toEqual(snapshot2);
});

test('should unsubscribe and re-subscribe to new function when subscribe function is changed', () => {
const snapshot = {count: 0};
const unsubscribe1 = jest.fn();
const unsubscribe2 = jest.fn();
const subscribe1 = jest.fn(() => unsubscribe1);
const subscribe2 = jest.fn(() => unsubscribe2);
const getSnapshot = jest.fn(() => snapshot);
const unsubscribe1 = vi.fn();
const unsubscribe2 = vi.fn();
const subscribe1 = vi.fn(() => unsubscribe1);
const subscribe2 = vi.fn(() => unsubscribe2);
const getSnapshot = vi.fn(() => snapshot);

const {rerender} = renderHook(
({subscribe}) => useSyncMemoizedStore(subscribe, getSnapshot),
Expand All @@ -71,10 +72,10 @@ describe('useSyncMemoizedStore', () => {
test('should replace current snapshot when getSnapshot function is changed', () => {
const snapshot1 = {count: 0};
const snapshot2 = {count: 1};
const unsubscribe = jest.fn();
const subscribe = jest.fn(() => unsubscribe);
const getSnapshot1 = jest.fn(() => snapshot1);
const getSnapshot2 = jest.fn(() => snapshot2);
const unsubscribe = vi.fn();
const subscribe = vi.fn(() => unsubscribe);
const getSnapshot1 = vi.fn(() => snapshot1);
const getSnapshot2 = vi.fn(() => snapshot2);

const {result, rerender} = renderHook(
({getSnapshot}) => useSyncMemoizedStore(subscribe, getSnapshot),
Expand All @@ -88,13 +89,13 @@ describe('useSyncMemoizedStore', () => {

it('should call the subscribe listener on mount and unsubscribe on unmount', () => {
const snapshot = {count: 0};
const unsubscribe = jest.fn();
const listener = jest.fn();
const subscribe = jest.fn(() => {
const unsubscribe = vi.fn();
const listener = vi.fn();
const subscribe = vi.fn(() => {
listener();
return unsubscribe;
});
const getSnapshot = jest.fn(() => snapshot);
const getSnapshot = vi.fn(() => snapshot);

const {result, unmount} = renderHook(() => {
return useSyncMemoizedStore(subscribe, getSnapshot);
Expand Down
19 changes: 15 additions & 4 deletions packages/headless-react/src/ssr/search-engine.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ import {
} from '@coveo/headless/ssr';
import {act, render, renderHook, screen} from '@testing-library/react';
import {PropsWithChildren} from 'react';
import {
vi,
expect,
describe,
test,
beforeEach,
MockInstance,
afterEach,
} from 'vitest';
import {MissingEngineProviderError} from './common.js';
import {defineSearchEngine} from './search-engine.js';

describe('Headless react SSR utils', () => {
let errorSpy: jest.SpyInstance;
let errorSpy: MockInstance;
const mockedNavigatorContextProvider: NavigatorContextProvider = () => {
return {
clientId: '123',
Expand All @@ -27,7 +36,7 @@ describe('Headless react SSR utils', () => {
};

beforeEach(() => {
errorSpy = jest.spyOn(console, 'error');
errorSpy = vi.spyOn(console, 'error');
});

afterEach(() => {
Expand Down Expand Up @@ -113,6 +122,8 @@ describe('Headless react SSR utils', () => {
const results = await screen.findAllByTestId(resultItemTestId);
expect(errorSpy).not.toHaveBeenCalled();
expect(results).toHaveLength(numResults);

results.forEach((result) => result.remove());
}

function checkRenderError(
Expand All @@ -121,7 +132,7 @@ describe('Headless react SSR utils', () => {
) {
let err: Error | undefined = undefined;
// Prevent expected error from being thrown in console when running tests
const consoleErrorStub = jest
const consoleErrorStub = vi
.spyOn(console, 'error')
.mockImplementation(() => {});
try {
Expand Down Expand Up @@ -248,7 +259,7 @@ describe('Headless react SSR utils', () => {
wrapper: hydratedStateProviderWrapper,
});
const initialState = result.current.state;
const controllerSpy = jest.spyOn(
const controllerSpy = vi.spyOn(
hydratedState.controllers.searchBox,
'updateText'
);
Expand Down
3 changes: 2 additions & 1 deletion packages/headless-react/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"moduleResolution": "NodeNext",
"module": "NodeNext",
"target": "ES2022",
"lib": ["dom", "ES2023"]
"lib": ["dom", "ES2023"],
"types": ["vitest/globals"]
},
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"],
"include": ["src/**/*.ts", "src/**/*.tsx"]
Expand Down
9 changes: 0 additions & 9 deletions packages/headless-react/tsconfig.test.json

This file was deleted.

8 changes: 8 additions & 0 deletions packages/headless-react/vitest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {defineConfig} from 'vitest/config';

/// <reference types="vitest/config" />
export default defineConfig({
test: {
environment: 'jsdom',
},
});
32 changes: 16 additions & 16 deletions packages/headless/doc-parser/src/interface-resolver.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
// eslint-disable-next-line n/no-unpublished-import
import {facetValueStates} from '../../src/features/facets/facet-api/value';
import {buildMockApiCallSignature} from '../mocks/mock-api-call-signature';
import {buildMockApiDocComment} from '../mocks/mock-api-doc-comment';
import {buildMockApiIndexSignature} from '../mocks/mock-api-index-signature';
import {buildMockApiInterface} from '../mocks/mock-api-interface';
import {buildMockApiMethodSignature} from '../mocks/mock-api-method-signature';
import {buildMockApiPropertySignature} from '../mocks/mock-api-property-signature';
import {buildMockApiTypeAlias} from '../mocks/mock-api-type-alias';
import {buildMockEntity} from '../mocks/mock-entity';
import {buildMockEntityWithTypeAlias} from '../mocks/mock-entity-with-type-alias';
import {buildMockEntryPoint} from '../mocks/mock-entry-point';
import {facetValueStates} from '../../src/features/facets/facet-api/value.js';
import {buildMockApiCallSignature} from '../mocks/mock-api-call-signature.js';
import {buildMockApiDocComment} from '../mocks/mock-api-doc-comment.js';
import {buildMockApiIndexSignature} from '../mocks/mock-api-index-signature.js';
import {buildMockApiInterface} from '../mocks/mock-api-interface.js';
import {buildMockApiMethodSignature} from '../mocks/mock-api-method-signature.js';
import {buildMockApiPropertySignature} from '../mocks/mock-api-property-signature.js';
import {buildMockApiTypeAlias} from '../mocks/mock-api-type-alias.js';
import {buildMockEntityWithTypeAlias} from '../mocks/mock-entity-with-type-alias.js';
import {buildMockEntity} from '../mocks/mock-entity.js';
import {buildMockEntryPoint} from '../mocks/mock-entry-point.js';
import {
buildContentExcerptToken,
buildReferenceExcerptToken,
} from '../mocks/mock-excerpt-token';
import {buildMockFuncEntity} from '../mocks/mock-func-entity';
import {buildMockObjEntity} from '../mocks/mock-obj-entity';
import {AnyEntity} from './entity';
import {resolveInterfaceMembers} from './interface-resolver';
} from '../mocks/mock-excerpt-token.js';
import {buildMockFuncEntity} from '../mocks/mock-func-entity.js';
import {buildMockObjEntity} from '../mocks/mock-obj-entity.js';
import {AnyEntity} from './entity.js';
import {resolveInterfaceMembers} from './interface-resolver.js';

describe('#resolveInterfaceMembers', () => {
it('resolves a property with a primitive type', () => {
Expand Down
9 changes: 0 additions & 9 deletions packages/headless/jest.config.cjs

This file was deleted.

11 changes: 4 additions & 7 deletions packages/headless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@
"build:bundles": "node esbuild.mjs",
"build:definitions": "tsc -p src/tsconfig.build.json -d --emitDeclarationOnly --declarationDir dist/definitions",
"clean": "rimraf -rf dist/*",
"test": "jest",
"test:watch": "jest --watch --colors --no-cache --silent=false",
"test:unit": "jest --testPathIgnorePatterns=src/integration-tests",
"test:integration": "jest --testPathPattern=src/integration-tests",
"test": "vitest run",
"test:watch": "vitest",
"publish:npm": "npm run-script -w=@coveo/release npm-publish",
"publish:bump": "npm run-script -w=@coveo/release bump",
"promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest",
Expand Down Expand Up @@ -169,9 +167,8 @@
"eslint-plugin-canonical": "4.18.0",
"execa": "8.0.1",
"install": "0.13.0",
"jest": "29.7.0",
"ts-jest": "29.2.3",
"ts-node": "10.9.2"
"ts-node": "10.9.2",
"vitest": "2.1.1"
},
"engines": {
"node": "^20.9.0"
Expand Down
20 changes: 10 additions & 10 deletions packages/headless/src/api/analytics/analytics-relay-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@ import {getAnalyticsNextApiBaseUrl} from '../platform-client.js';
import {getRelayInstanceFromState} from './analytics-relay-client.js';
import {getAnalyticsSource} from './analytics-selectors.js';

jest.mock('@coveo/relay');
jest.mock('./analytics-selectors');
vi.mock('@coveo/relay');
vi.mock('./analytics-selectors');

describe('#getRelayInstanceFromState', () => {
const mockedCreateRelay = jest.mocked(createRelay).mockImplementation(() => ({
emit: jest.fn(),
on: jest.fn(),
off: jest.fn(),
getMeta: jest.fn(),
updateConfig: jest.fn(),
const mockedCreateRelay = vi.mocked(createRelay).mockImplementation(() => ({
emit: vi.fn(),
on: vi.fn(),
off: vi.fn(),
getMeta: vi.fn(),
updateConfig: vi.fn(),
version: 'test',
}));

beforeEach(() => {
jest.mocked(getAnalyticsSource).mockReturnValue(['baguette']);
vi.mocked(getAnalyticsSource).mockReturnValue(['baguette']);
});

afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});

it('creates a Relay client properly and returns it', () => {
Expand Down
10 changes: 5 additions & 5 deletions packages/headless/src/api/analytics/search-analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ import {
StateNeededBySearchAnalyticsProvider,
} from './search-analytics.js';

jest.mock('@coveo/relay');
vi.mock('@coveo/relay');

const mockGetHistory = jest.fn();
const mockGetHistory = vi.fn();

jest.mock('coveo.analytics', () => {
const originalModule = jest.requireActual('coveo.analytics');
vi.mock('coveo.analytics', async () => {
const originalModule = await vi.importActual('coveo.analytics');
return {
...originalModule,
history: {
HistoryStore: jest.fn().mockImplementation(() => {
HistoryStore: vi.fn().mockImplementation(() => {
return {
getHistory: () => mockGetHistory(),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {Mock} from 'vitest';
import {SortBy} from '../../features/sort/sort.js';
import {buildMockCommerceAPIClient} from '../../test/mock-commerce-api-client.js';
import {VERSION} from '../../utils/version.js';
Expand All @@ -17,18 +18,18 @@ describe('commerce api client', () => {
const trackingId = 'some-tracking-id';

let client: CommerceAPIClient;
let platformCallMock: jest.Mock;
let platformCallMock: Mock;

beforeEach(() => {
client = buildMockCommerceAPIClient();
});

afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});

const mockPlatformCall = (fakeResponse: unknown) => {
platformCallMock = jest.fn();
platformCallMock = vi.fn();

platformCallMock.mockReturnValue(fakeResponse);
PlatformClient.call = platformCallMock;
Expand Down
Loading
Loading