Skip to content

Commit

Permalink
Merge branch 'fetch_api_infra' into namespace-ui
Browse files Browse the repository at this point in the history
Signed-off-by: yelias <[email protected]>
  • Loading branch information
yelias committed Jan 5, 2025
2 parents 8d0a137 + dd4555a commit f830c37
Show file tree
Hide file tree
Showing 32 changed files with 1,953 additions and 235 deletions.
4 changes: 4 additions & 0 deletions workspaces/frontend/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ module.exports = {
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
snapshotSerializers: [],

setupFilesAfterEnv: ['<rootDir>/src/__tests__/unit/jest.setup.ts'],

preset: 'ts-jest',

coverageDirectory: 'jest-coverage',

collectCoverageFrom: [
Expand Down
532 changes: 336 additions & 196 deletions workspaces/frontend/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions workspaces/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"devDependencies": {
"@cypress/code-coverage": "^3.13.5",
"@testing-library/cypress": "^10.0.1",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "14.4.3",
Expand All @@ -47,6 +48,7 @@
"chai-subset": "^1.6.0",
"concurrently": "^9.1.0",
"copy-webpack-plugin": "^11.0.0",
"core-js": "^3.39.0",
"css-loader": "^6.11.0",
"css-minimizer-webpack-plugin": "^5.0.1",
"cypress": "^13.15.0",
Expand All @@ -56,6 +58,7 @@
"cypress-multi-reporters": "^2.0.4",
"dotenv": "^16.4.5",
"dotenv-webpack": "^8.1.0",
"expect": "^29.7.0",
"html-webpack-plugin": "^5.6.0",
"imagemin": "^8.0.1",
"jest": "^29.7.0",
Expand Down
7 changes: 7 additions & 0 deletions workspaces/frontend/src/__mocks__/mockNamespaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NamespacesList } from '~/app/types';

export const mockNamespaces: NamespacesList = [
{ name: 'default' },
{ name: 'kubeflow' },
{ name: 'custom-namespace' },
];
1 change: 1 addition & 0 deletions workspaces/frontend/src/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
5 changes: 5 additions & 0 deletions workspaces/frontend/src/__mocks__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ResponseBody } from '~/app/types';

export const mockBFFResponse = <T>(data: T): ResponseBody<T> => ({
data,
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { mockNamespaces } from '~/__mocks__/mockNamespaces';
import { mockBFFResponse } from '~/__mocks__/utils';

const namespaces = ['default', 'kubeflow', 'custom-namespace'];
const mockNamespaces = {
data: [{ name: 'default' }, { name: 'kubeflow' }, { name: 'custom-namespace' }],
};

describe('Namespace Selector Dropdown', () => {
beforeEach(() => {
// Mock the namespaces and selected namespace
// Mock the namespaces API response
cy.intercept('GET', '/api/v1/namespaces', {
body: mockNamespaces,
});
body: mockBFFResponse(mockNamespaces),
}).as('getNamespaces');
cy.visit('/');
cy.wait('@getNamespaces');
});

it('should open the namespace dropdown and select a namespace', () => {
Expand Down Expand Up @@ -38,4 +39,19 @@ describe('Namespace Selector Dropdown', () => {
cy.get('[data-testid="nav-link-/notebookSettings"]').click();
cy.get('[data-testid="namespace-toggle"]').should('contain', 'custom-namespace');
});

it('should filter namespaces based on search input', () => {
cy.get('[data-testid="namespace-toggle"]').click();
cy.get('[data-testid="namespace-search-input"]').type('custom')

Check failure on line 45 in workspaces/frontend/src/__tests__/cypress/cypress/tests/e2e/NamespaceSelector.cy.ts

View workflow job for this annotation

GitHub Actions / test-and-build

Insert `;`
cy.get('[data-testid="namespace-search-input"] input').should('have.value', 'custom');
cy.get('[data-testid="namespace-search-button"]').click();
// Verify that only the matching namespace is displayed
namespaces.forEach((ns) => {
if (ns === 'custom-namespace') {
cy.get(`[data-testid="dropdown-item-${ns}"]`).should('exist').and('contain', ns);
} else {
cy.get(`[data-testid="dropdown-item-${ns}"]`).should('not.exist');
}
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { pageNotfound } from '~/__tests__/cypress/cypress/pages/pageNotFound';
import { home } from '~/__tests__/cypress/cypress/pages/home';
import { mockNamespaces } from '~/__mocks__/mockNamespaces';
import { mockBFFResponse } from '~/__mocks__/utils';

describe('Application', () => {
beforeEach(() => {
// Mock the namespaces API response
cy.intercept('GET', '/api/v1/namespaces', {
body: mockBFFResponse(mockNamespaces),
}).as('getNamespaces');
cy.visit('/');
cy.wait('@getNamespaces');
});

it('Page not found should render', () => {
pageNotfound.visit();
});
Expand Down
29 changes: 29 additions & 0 deletions workspaces/frontend/src/__tests__/unit/jest.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
declare namespace jest {
interface Expect {
isIdentityEqual: <T>(expected: T) => T;
}

interface Matchers<R, T> {
hookToBe: (expected: unknown) => R;
hookToStrictEqual: (expected: unknown) => R;
hookToHaveUpdateCount: (expected: number) => R;
hookToBeStable: <
V extends T extends Pick<
import('~/__tests__/unit/testUtils/hooks').RenderHookResultExt<
infer Result,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
any
>,
'result'
>
? import('~/__tests__/unit/testUtils/hooks').BooleanValues<Result>
: never,
>(
expected?: V,
) => R;
}

interface Expect {
isIdentityEqual: (expected: unknown) => AsymmetricMatcher;
}
}
66 changes: 66 additions & 0 deletions workspaces/frontend/src/__tests__/unit/jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { TextEncoder } from 'util';
import { JestAssertionError } from 'expect';
import 'core-js/actual/array/to-sorted';
import {
BooleanValues,
RenderHookResultExt,
createComparativeValue,
} from '~/__tests__/unit/testUtils/hooks';

global.TextEncoder = TextEncoder;

const tryExpect = (expectFn: () => void) => {
try {
expectFn();
} catch (e) {
const { matcherResult } = e as JestAssertionError;
if (matcherResult) {
return { ...matcherResult, message: () => matcherResult.message };
}
throw e;
}
return {
pass: true,
message: () => '',
};
};

expect.extend({
// custom asymmetric matchers

/**
* Checks that a value is what you expect.
* It uses Object.is to check strict equality.
*
* Usage:
* expect.isIdentifyEqual(...)
*/
isIdentityEqual: (actual, expected) => ({
pass: Object.is(actual, expected),
message: () => `expected ${actual} to be identity equal to ${expected}`,
}),

// hook related custom matchers
hookToBe: (actual: RenderHookResultExt<unknown, unknown>, expected) =>
tryExpect(() => expect(actual.result.current).toBe(expected)),

hookToStrictEqual: (actual: RenderHookResultExt<unknown, unknown>, expected) =>
tryExpect(() => expect(actual.result.current).toStrictEqual(expected)),

hookToHaveUpdateCount: (actual: RenderHookResultExt<unknown, unknown>, expected: number) =>
tryExpect(() => expect(actual.getUpdateCount()).toBe(expected)),

hookToBeStable: <R>(actual: RenderHookResultExt<R, unknown>, expected?: BooleanValues<R>) => {
if (actual.getUpdateCount() <= 1) {
throw new Error('Cannot assert stability as the hook has not run at least 2 times.');
}
if (typeof expected === 'undefined') {
return tryExpect(() => expect(actual.result.current).toBe(actual.getPreviousResult()));
}
return tryExpect(() =>
expect(actual.result.current).toStrictEqual(
createComparativeValue(actual.getPreviousResult(), expected),
),
);
},
});
Loading

0 comments on commit f830c37

Please sign in to comment.