Skip to content
Open
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
8 changes: 8 additions & 0 deletions nexus/frontend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
1 change: 1 addition & 0 deletions nexus/frontend/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('@testing-library/jest-dom');
9 changes: 8 additions & 1 deletion nexus/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"build": "next build",
"start": "next start -H 0.0.0.0 -p ${PORT:-3000}",
"lint": "node -e \"process.env.NODE_PATH=require('path').resolve('node_modules'); require('module').Module._initPaths(); require('child_process').execSync('npx eslint src', {stdio:'inherit', env: {...process.env, NODE_PATH: require('path').resolve('node_modules')}})\"",
"lint:strict": "npm run lint"
"lint:strict": "npm run lint",
"test": "jest"
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
Expand Down Expand Up @@ -42,13 +43,19 @@
"zod": "^4.3.6"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
Comment on lines +46 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update the root workspace lockfile for the new Jest deps

Because /workspace/ERP/package.json declares nexus/frontend as a workspace, root-level installs use /workspace/ERP/package-lock.json, not the newly added nexus/package-lock.json. That existing root lock still has no entries for the newly added frontend test deps such as @testing-library/jest-dom, @testing-library/react, or jest-environment-jsdom, and npm ci is documented to error when package.json and the package lock disagree; CI/dev flows that run npm ci --workspace nexus/frontend from the repo root will not get a reproducible install for the new npm test script. Please update the root lockfile alongside these deps.

Useful? React with 👍 / 👎.

"@types/babel__traverse": "^7.28.0",
"@types/jest": "^30.0.0",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"jest": "^30.4.0",
"jest-environment-jsdom": "^30.4.0",
"tailwindcss": "^3.4.1",
"ts-jest": "^29.4.9",
"typescript": "^5"
}
}
10 changes: 10 additions & 0 deletions nexus/frontend/src/lib/network-consent.node.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @jest-environment node
*/
describe('network-consent (node)', () => {
it('should return true when window is undefined', async () => {
jest.resetModules();
const networkConsentModule = await import('./network-consent');
expect(networkConsentModule.hasNetworkConsent()).toBe(true);
});
});
71 changes: 71 additions & 0 deletions nexus/frontend/src/lib/network-consent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
describe('network-consent', () => {
let hasNetworkConsent: typeof import('./network-consent').hasNetworkConsent;

beforeEach(async () => {
jest.resetModules();
const networkConsentModule = await import('./network-consent');
hasNetworkConsent = networkConsentModule.hasNetworkConsent;
// Clear out any mocked window.sessionStorage between tests
// @ts-expect-error Type deletion is fine in tests to clean mock overrides
delete window.sessionStorage;
});

afterEach(() => {
jest.restoreAllMocks();
});

describe('hasNetworkConsent', () => {
it('should return false if sessionStorage is empty and cache is not set', async () => {
const mockGetItem = jest.fn().mockReturnValue(null);
Object.defineProperty(window, 'sessionStorage', {
value: { getItem: mockGetItem },
writable: true,
configurable: true,
});

expect(hasNetworkConsent()).toBe(false);
expect(mockGetItem).toHaveBeenCalledWith('k_network_consent_granted');
});

it('should return true if sessionStorage has granted', async () => {
const mockGetItem = jest.fn().mockReturnValue('granted');
Object.defineProperty(window, 'sessionStorage', {
value: { getItem: mockGetItem },
writable: true,
configurable: true,
});

expect(hasNetworkConsent()).toBe(true);
expect(mockGetItem).toHaveBeenCalledWith('k_network_consent_granted');
});

it('should return false if sessionStorage throws an error', async () => {
Object.defineProperty(window, 'sessionStorage', {
get: () => {
throw new Error('Access denied');
},
configurable: true,
});

expect(hasNetworkConsent()).toBe(false);
});

it('should use consentCache if already set', async () => {
// First call to set the cache
const mockGetItem = jest.fn().mockReturnValue('granted');
Object.defineProperty(window, 'sessionStorage', {
value: { getItem: mockGetItem },
writable: true,
configurable: true,
});

expect(hasNetworkConsent()).toBe(true);
expect(mockGetItem).toHaveBeenCalledTimes(1);

// Change session storage, shouldn't be called because cache is true
mockGetItem.mockReturnValue(null);
expect(hasNetworkConsent()).toBe(true);
expect(mockGetItem).toHaveBeenCalledTimes(1); // Still 1
});
});
});
Loading