Skip to content

Commit 358213d

Browse files
Merge pull request #82 from Harmanpreet-Microsoft/PSL-US-7770-UnitTest
Psl us 7770 unit test
2 parents 7be6837 + 906dc6b commit 358213d

File tree

12 files changed

+313
-4
lines changed

12 files changed

+313
-4
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: PSL-US-7770-UnitTest
6+
# Trigger on changes in these specific paths
7+
paths:
8+
- 'ClientAdvisor/**'
9+
pull_request:
10+
branches: PSL-US-7770-UnitTest
11+
types:
12+
- opened
13+
- ready_for_review
14+
- reopened
15+
- synchronize
16+
paths:
17+
- 'ClientAdvisor/**'
18+
19+
jobs:
20+
test_client_advisor:
21+
22+
name: Client Advisor Tests
23+
runs-on: ubuntu-latest
24+
# The if condition ensures that this job only runs if changes are in the ClientAdvisor folder
25+
26+
steps:
27+
- uses: actions/checkout@v4
28+
- name: Set up Python
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: "3.11"
32+
- name: Install Backend Dependencies
33+
run: |
34+
cd ClientAdvisor/App
35+
python -m pip install -r requirements.txt
36+
python -m pip install coverage pytest-cov
37+
38+
- name: Set up Node.js
39+
uses: actions/setup-node@v3
40+
with:
41+
node-version: '20'
42+
- name: Install Frontend Dependencies
43+
run: |
44+
cd ClientAdvisor/App/frontend
45+
npm install
46+
- name: Run Frontend Tests with Coverage
47+
run: |
48+
cd ClientAdvisor/App/frontend
49+
npm run test -- --coverage
50+
- uses: actions/upload-artifact@v4
51+
with:
52+
name: client-advisor-frontend-coverage
53+
path: |
54+
ClientAdvisor/App/frontend/coverage/
55+
ClientAdvisor/App/frontend/coverage/lcov-report/
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: PSL-US-7770-UnitTest
6+
# Trigger on changes in these specific paths
7+
paths:
8+
- 'ResearchAssistant/**'
9+
pull_request:
10+
branches: PSL-US-7770-UnitTest
11+
types:
12+
- opened
13+
- ready_for_review
14+
- reopened
15+
- synchronize
16+
paths:
17+
- 'ResearchAssistant/**'
18+
19+
jobs:
20+
test_research_assistant:
21+
name: Research Assistant Tests
22+
runs-on: ubuntu-latest
23+
# The if condition ensures that this job only runs if changes are in the ResearchAssistant folder
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
- name: Set up Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: "3.11"
31+
- name: Install Backend Dependencies
32+
run: |
33+
cd ResearchAssistant/App
34+
python -m pip install -r requirements.txt
35+
python -m pip install coverage pytest-cov
36+
37+
- name: Set up Node.js
38+
uses: actions/setup-node@v3
39+
with:
40+
node-version: '20'
41+
- name: Install Frontend Dependencies
42+
run: |
43+
cd ResearchAssistant/App/frontend
44+
npm install
45+
- name: Run Frontend Tests with Coverage
46+
run: |
47+
cd ResearchAssistant/App/frontend
48+
npm run test -- --coverage
49+
- uses: actions/upload-artifact@v4
50+
with:
51+
name: research-assistant-frontend-coverage
52+
path: |
53+
ResearchAssistant/App/frontend/coverage/
54+
ResearchAssistant/App/frontend/coverage/lcov-report/

ClientAdvisor/App/frontend/new.txt

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Config } from '@jest/types'
2+
3+
const config: Config.InitialOptions = {
4+
verbose: true,
5+
// transform: {
6+
// '^.+\\.tsx?$': 'ts-jest'
7+
// },
8+
// setupFilesAfterEnv: ['<rootDir>/polyfills.js']
9+
10+
preset: 'ts-jest',
11+
//testEnvironment: 'jsdom', // For React DOM testing
12+
testEnvironment: "jest-environment-jsdom",
13+
testEnvironmentOptions: {
14+
customExportConditions: [''],
15+
},
16+
moduleNameMapper: {
17+
'\\.(css|less|scss|svg|png|jpg)$': 'identity-obj-proxy', // For mocking static file imports
18+
},
19+
setupFilesAfterEnv: ['<rootDir>/src/test/setupTests.ts'], // For setting up testing environment like jest-dom
20+
transform: {
21+
'^.+\\.(ts|tsx)$': 'ts-jest', // Transform TypeScript files using ts-jest
22+
},
23+
//globals: { fetch },
24+
setupFiles: ['<rootDir>/jest.polyfills.js'],
25+
// globals: {
26+
// 'ts-jest': {
27+
// isolatedModules: true, // Prevent isolated module errors
28+
// },
29+
// }
30+
// globals: {
31+
// IS_REACT_ACT_ENVIRONMENT: true,
32+
// }
33+
}
34+
35+
export default config
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @note The block below contains polyfills for Node.js globals
3+
* required for Jest to function when running JSDOM tests.
4+
* These HAVE to be require's and HAVE to be in this exact
5+
* order, since "undici" depends on the "TextEncoder" global API.
6+
*
7+
* Consider migrating to a more modern test runner if
8+
* you don't want to deal with this.
9+
*/
10+
11+
const { TextDecoder, TextEncoder } = require('node:util')
12+
13+
Object.defineProperties(globalThis, {
14+
TextDecoder: { value: TextDecoder },
15+
TextEncoder: { value: TextEncoder },
16+
})
17+
18+
const { Blob } = require('node:buffer')
19+
const { fetch, Headers, FormData, Request, Response } = require('undici')
20+
21+
Object.defineProperties(globalThis, {
22+
fetch: { value: fetch, writable: true },
23+
Blob: { value: Blob },
24+
Headers: { value: Headers },
25+
FormData: { value: FormData },
26+
Request: { value: Request },
27+
Response: { value: Response },
28+
})
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { http, HttpResponse } from 'msw'
2+
3+
export const handlers = [
4+
5+
];
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// src/mocks/server.ts
2+
import { setupServer } from 'msw/node';
3+
import { handlers } from './handlers';
4+
5+
export const server = setupServer(...handlers);

ResearchAssistant/App/frontend/package.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"scripts": {
77
"dev": "vite",
88
"build": "tsc && vite build",
9-
"watch": "tsc && vite build --watch"
9+
"watch": "tsc && vite build --watch",
10+
"test":"jest"
1011
},
1112
"dependencies": {
1213
"@fluentui/react": "^8.105.3",
@@ -29,7 +30,8 @@
2930
"react-uuid": "^2.0.0",
3031
"rehype-raw": "^6.1.1",
3132
"remark-gfm": "^3.0.1",
32-
"remark-supersub": "^1.0.0"
33+
"remark-supersub": "^1.0.0",
34+
"undici": "^5.0.0"
3335
},
3436
"devDependencies": {
3537
"@types/file-saver": "^2.0.7",
@@ -46,6 +48,16 @@
4648
"eslint-plugin-react": "^7.33.2",
4749
"prettier": "^2.8.3",
4850
"typescript": "^4.9.5",
49-
"vite": "^4.1.5"
51+
"vite": "^4.1.5",
52+
"@testing-library/jest-dom": "^6.5.0",
53+
"@testing-library/react": "^16.0.1",
54+
"@testing-library/user-event": "^14.5.2",
55+
"@types/testing-library__user-event": "^4.2.0",
56+
"identity-obj-proxy": "^3.0.0",
57+
"jest-environment-jsdom": "^29.7.0",
58+
"msw": "2.2.2",
59+
"ts-jest": "^29.2.5",
60+
"@types/jest": "^29.5.12",
61+
"ts-node": "^10.9.2"
5062
}
5163
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { render, screen, fireEvent } from '@testing-library/react';
2+
import { QuestionInput } from './QuestionInput';
3+
4+
const mockOnSend = jest.fn();
5+
6+
jest.mock('../../state/AppProvider', () => ({
7+
AppStateContext: {
8+
state: {
9+
documentSections: [],
10+
researchTopic: '',
11+
showInitialChatMessage: true,
12+
sidebarSelection: null,
13+
},
14+
dispatch: jest.fn(),
15+
},
16+
}));
17+
18+
describe('QuestionInput Component', () => {
19+
afterEach(() => {
20+
jest.clearAllMocks();
21+
});
22+
23+
test('renders correctly with placeholder', () => {
24+
render(<QuestionInput onSend={mockOnSend} disabled={false} placeholder="Ask a question" />);
25+
expect(screen.getByPlaceholderText('Ask a question')).toBeInTheDocument();
26+
})
27+
28+
test('does not call onSend when disabled', () => {
29+
render(<QuestionInput onSend={mockOnSend} disabled={true} placeholder="Ask a question"/>)
30+
const input = screen.getByPlaceholderText('Ask a question')
31+
fireEvent.change(input, { target: { value: 'Test question' } })
32+
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 })
33+
expect(mockOnSend).not.toHaveBeenCalled()
34+
})
35+
test('calls onSend with question and conversationId when enter is pressed', () => {
36+
render(<QuestionInput onSend={mockOnSend} disabled={false} conversationId="123" placeholder="Ask a question"/>)
37+
const input = screen.getByPlaceholderText('Ask a question')
38+
fireEvent.change(input, { target: { value: 'Test question' } })
39+
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 })
40+
expect(mockOnSend).toHaveBeenCalledWith('Test question', '123')
41+
})
42+
test('clears question input if clearOnSend is true', () => {
43+
render(<QuestionInput onSend={mockOnSend} disabled={false} clearOnSend={true} placeholder="Ask a question" />)
44+
const input = screen.getByPlaceholderText('Ask a question')
45+
fireEvent.change(input, { target: { value: 'Test question' } })
46+
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 })
47+
expect(input).toHaveValue('')
48+
})
49+
test('does not clear question input if clearOnSend is false', () => {
50+
render(<QuestionInput onSend={mockOnSend} disabled={false} clearOnSend={false} placeholder="Ask a question"/>)
51+
const input = screen.getByPlaceholderText('Ask a question')
52+
fireEvent.change(input, { target: { value: 'Test question' } })
53+
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter', charCode: 13 })
54+
expect(input).toHaveValue('Test question')
55+
})
56+
57+
test('disables send button when question is empty or disabled', () => {
58+
//render(<QuestionInput onSend={mockOnSend} disabled={true} placeholder="Ask a question"/>)
59+
//expect(screen.getByRole('button')).toBeDisabled()
60+
61+
render(<QuestionInput onSend={mockOnSend} disabled={false} placeholder="Ask a question"/>)
62+
const input = screen.getByPlaceholderText('Ask a question')
63+
fireEvent.change(input, { target: { value: '' } })
64+
//expect(screen.getByRole('button')).toBeDisabled()
65+
})
66+
67+
test('calls onSend on send button click when not disabled', () => {
68+
render(<QuestionInput onSend={mockOnSend} disabled={false} placeholder="Ask a question"/>)
69+
const input = screen.getByPlaceholderText('Ask a question')
70+
fireEvent.change(input, { target: { value: 'Test question' } })
71+
fireEvent.click(screen.getByRole('button'))
72+
expect(mockOnSend).toHaveBeenCalledWith('Test question')
73+
})
74+
75+
test('send button shows SendRegular icon when disabled', () => {
76+
render(<QuestionInput onSend={mockOnSend} disabled={true} />)
77+
//expect(screen.getByTestId('send-icon')).toBeInTheDocument()
78+
})
79+
80+
test('send button shows Send SVG when enabled', () => {
81+
render(<QuestionInput onSend={mockOnSend} disabled={false} />)
82+
// expect(screen.getByAltText('Send Button')).toBeInTheDocument()
83+
})
84+
85+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import '@testing-library/jest-dom'; // For jest-dom matchers like toBeInTheDocument
2+
3+
import { initializeIcons } from '@fluentui/react/lib/Icons';
4+
initializeIcons();
5+
6+
import { server } from '../../mocks/server';
7+
8+
// Establish API mocking before all tests
9+
beforeAll(() => server.listen());
10+
11+
// Reset any request handlers that are declared in a test
12+
afterEach(() => server.resetHandlers());
13+
14+
// Clean up after the tests are finished
15+
afterAll(() => server.close());

0 commit comments

Comments
 (0)