Skip to content

Commit cda2908

Browse files
author
Ben Warzeski
authored
Merge pull request #10 from openedx/bw/ts_new_api
Bw/ts new api
2 parents 1343452 + 8da1ff9 commit cda2908

File tree

18 files changed

+1614
-789
lines changed

18 files changed

+1614
-789
lines changed

.eslintignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
coverage/*
22
dist/
33
node_modules/
4-
jest.config.js
4+
jest.config.js
5+
webpack.*.js
6+
.eslintrc.js

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
with:
2323
node-version: ${{ env.NODE_VER }}
2424
- name: Install dependencies
25-
run: npm ci
25+
run: npm ci --legacy-peer-deps
2626
- name: Lint
2727
run: npm run lint
2828
- name: Test

.github/workflows/commitlint.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,14 @@ on:
77

88
jobs:
99
commitlint:
10-
uses: openedx/.github/.github/workflows/commitlint.yml@master
10+
runs-on: ubuntu-20.04
11+
steps:
12+
- name: Check out repository
13+
uses: actions/checkout@v3
14+
with:
15+
fetch-depth: 0
16+
- name: remove tsconfig.json # see issue https://github.com/conventional-changelog/commitlint/issues/3256
17+
run: |
18+
rm tsconfig.json
19+
- name: Check commits
20+
uses: wagoid/commitlint-github-action@v5

jest.config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { createConfig } = require('@edx/frontend-build');
22

3-
module.exports = createConfig('jest', {
3+
const config = createConfig('jest', {
44
// setupFilesAfterEnv is used after the jest environment has been loaded. In general this is what you want.
55
// If you want to add config BEFORE jest loads, use setupFiles instead.
66
setupFilesAfterEnv: [
@@ -11,3 +11,8 @@ module.exports = createConfig('jest', {
1111
'src/i18n',
1212
],
1313
});
14+
15+
config.moduleDirectories = ['node_modules', 'src'];
16+
// config.moduleNameMapper['@/(.*)'] = '<rootDir>/src/$1';
17+
18+
module.exports = config;

package-lock.json

Lines changed: 1031 additions & 715 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@edx/paragon": "^20.20.0",
4141
"@edx/react-unit-test-utils": "1.5.3",
4242
"@edx/tinymce-language-selector": "1.1.0",
43+
"@edx/typescript-config": "^1.0.1",
4344
"@fortawesome/fontawesome-svg-core": "1.2.36",
4445
"@fortawesome/free-brands-svg-icons": "5.15.4",
4546
"@fortawesome/free-regular-svg-icons": "5.15.4",
@@ -50,6 +51,7 @@
5051
"classnames": "^2.3.2",
5152
"core-js": "3.31.1",
5253
"filesize": "^8.0.6",
54+
"jest-when": "^3.6.0",
5355
"prop-types": "15.8.1",
5456
"query-string": "^8.1.0",
5557
"react": "16.14.0",
@@ -65,10 +67,11 @@
6567
},
6668
"devDependencies": {
6769
"@edx/browserslist-config": "^1.1.1",
68-
"@edx/frontend-build": "12.9.4",
70+
"@edx/frontend-build": "12.9.0-alpha.6",
6971
"@edx/reactifex": "^2.1.1",
7072
"glob": "7.2.3",
7173
"husky": "7.0.4",
72-
"jest": "29.6.2"
74+
"jest": "29.6.2",
75+
"ts-jest": "^26.5.6"
7376
}
7477
}

src/data/services/lms/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const feedbackRequirement = StrictDict({
88

99
export const queryKeys = StrictDict({
1010
oraConfig: 'oraConfig',
11-
submissionData: 'submissionData',
11+
pageData: 'pageData',
1212
});
1313

1414
export default { feedbackRequirement, queryKeys };
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { useQuery } from '@tanstack/react-query';
2+
import { useRouteMatch } from 'react-router-dom';
3+
import { camelCaseObject } from '@edx/frontend-platform';
4+
import { when } from 'jest-when';
5+
6+
import routes from 'routes';
7+
import * as types from '../types';
8+
import { queryKeys } from '../constants';
9+
import fakeData from '../fakeData';
10+
11+
import { useORAConfig, usePageData } from './api';
12+
13+
jest.mock('@tanstack/react-query', () => ({ useQuery: jest.fn() }));
14+
15+
jest.mock('react-router-dom', () => ({ useRouteMatch: jest.fn() }));
16+
17+
interface QueryFn { (): string }
18+
interface QueryArgs { queryKey: string, queryFn: QueryFn }
19+
20+
interface MockORAQuery extends QueryArgs { data: types.ORAConfig }
21+
interface MockUseORAQuery { (QueryArgs): MockORAQuery }
22+
interface MockORAUseConfigHook { (): MockORAQuery }
23+
24+
interface MockPageDataQuery extends QueryArgs { data: types.PageData }
25+
interface MockUsePageDataQuery { (QueryArgs): MockPageDataQuery }
26+
interface MockPageDataUseConfigHook { (): MockPageDataQuery }
27+
28+
let out;
29+
describe('lms api hooks', () => {
30+
describe('useORAConfig', () => {
31+
const mockUseQuery = (hasData: boolean): MockUseORAQuery => ({ queryKey, queryFn }) => ({
32+
data: hasData ? camelCaseObject(fakeData.oraConfig.assessmentText) : undefined,
33+
queryKey,
34+
queryFn,
35+
});
36+
37+
const mockUseQueryForORA = (hasData) => {
38+
when(useQuery)
39+
.calledWith(expect.objectContaining({ queryKey: [queryKeys.oraConfig] }))
40+
.mockImplementationOnce(mockUseQuery(hasData));
41+
};
42+
43+
const testUseORAConfig = useORAConfig as unknown as MockORAUseConfigHook;
44+
45+
beforeEach(() => {
46+
mockUseQueryForORA(true);
47+
out = testUseORAConfig();
48+
});
49+
it('initializes query with oraConfig queryKey', () => {
50+
expect(out.queryKey).toEqual([queryKeys.oraConfig]);
51+
});
52+
it('initializes query with promise pointing to assessment text', async () => {
53+
const response = await out.queryFn();
54+
expect(response).toEqual(fakeData.oraConfig.assessmentText);
55+
});
56+
it('returns camelCase object from data if data has been returned', () => {
57+
expect(out.data).toEqual(camelCaseObject(fakeData.oraConfig.assessmentText));
58+
});
59+
it('returns empty object from data if data has not been returned', () => {
60+
mockUseQueryForORA(false);
61+
out = testUseORAConfig();
62+
expect(out.data).toEqual({});
63+
});
64+
});
65+
describe('usePageData', () => {
66+
const mockUseQuery = (data?: types.PageData): MockUsePageDataQuery => ({ queryKey, queryFn }) => ({
67+
data: data ? camelCaseObject(data) : undefined,
68+
queryKey,
69+
queryFn,
70+
});
71+
72+
const mockUseQueryForPageData = (data, isAssessment) => {
73+
when(useQuery)
74+
.calledWith(expect.objectContaining({ queryKey: [queryKeys.pageData, isAssessment] }))
75+
.mockImplementationOnce(mockUseQuery(data));
76+
};
77+
78+
const mockUseRouteMatch = (path) => {
79+
when(useRouteMatch)
80+
.calledWith()
81+
.mockReturnValueOnce({ path });
82+
};
83+
84+
const testUsePageData = usePageData as unknown as MockPageDataUseConfigHook;
85+
describe('submission', () => {
86+
beforeEach(() => {
87+
mockUseRouteMatch(routes.submission);
88+
mockUseQueryForPageData(fakeData.pageData.shapes.emptySubmission, false);
89+
out = testUsePageData();
90+
});
91+
it('initializes query with pageData queryKey and isAssessment: false', () => {
92+
expect(out.queryKey).toEqual([queryKeys.pageData, false]);
93+
});
94+
it('initializes query with promise pointing to empty submission page data', async () => {
95+
const response = await out.queryFn();
96+
expect(response).toEqual(fakeData.pageData.shapes.emptySubmission);
97+
});
98+
it('returns camelCase object from data if data has been returned', () => {
99+
expect(out.data).toEqual(camelCaseObject(fakeData.pageData.shapes.emptySubmission));
100+
});
101+
});
102+
describe('assessment', () => {
103+
beforeEach(() => {
104+
mockUseRouteMatch(routes.assessment);
105+
mockUseQueryForPageData(fakeData.pageData.shapes.peerAssessment, true);
106+
out = testUsePageData();
107+
});
108+
it('initializes query with pageData queryKey and isAssessment: true', () => {
109+
expect(out.queryKey).toEqual([queryKeys.pageData, true]);
110+
});
111+
it('initializes query with promise pointing to peer assessment page data', async () => {
112+
const response = await out.queryFn();
113+
expect(response).toEqual(fakeData.pageData.shapes.peerAssessment);
114+
});
115+
it('returns camelCase object from data if data has been returned', () => {
116+
expect(out.data).toEqual(camelCaseObject(fakeData.pageData.shapes.peerAssessment));
117+
});
118+
});
119+
it('returns empty object from data if data has not been returned', () => {
120+
mockUseRouteMatch(routes.submission);
121+
mockUseQueryForPageData(undefined, false);
122+
out = testUsePageData();
123+
expect(out.data).toEqual({});
124+
});
125+
});
126+
});

src/data/services/lms/hooks/api.js renamed to src/data/services/lms/hooks/api.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { useRouteMatch } from 'react-router-dom';
44
import { camelCaseObject } from '@edx/frontend-platform';
55

66
import routes from 'routes';
7+
import * as types from '../types';
78
import { queryKeys } from '../constants';
89
import fakeData from '../fakeData';
910

10-
export const useORAConfig = () => {
11+
export const useORAConfig = (): types.QueryData<types.ORAConfig> => {
1112
const { data, ...status } = useQuery({
1213
queryKey: [queryKeys.oraConfig],
1314
// queryFn: () => getAuthenticatedClient().get(...),
@@ -19,29 +20,17 @@ export const useORAConfig = () => {
1920
};
2021
};
2122

22-
export const usePageData = () => {
23+
export const usePageData = (): types.QueryData<types.PageData> => {
2324
const route = useRouteMatch();
2425
const isAssessment = route.path === routes.assessment;
2526
const returnData = isAssessment
2627
? fakeData.pageData.shapes.peerAssessment
2728
: fakeData.pageData.shapes.emptySubmission;
28-
console.log({ returnData, isAssessment, route });
29-
const { data, ...status } = useQuery({
30-
queryKey: [queryKeys.submissionData, isAssessment],
31-
// queryFn: () => getAuthenticatedClient().get(...),
32-
queryFn: () => Promise.resolve(returnData),
33-
});
34-
return {
35-
...status,
36-
data: data ? camelCaseObject(data) : {},
37-
};
38-
};
3929

40-
export const useAssessmentData = () => {
4130
const { data, ...status } = useQuery({
42-
queryKey: [queryKeys.submissionData],
31+
queryKey: [queryKeys.pageData, isAssessment],
4332
// queryFn: () => getAuthenticatedClient().get(...),
44-
queryFn: () => Promise.resolve(fakeData.submission.teamAssessment),
33+
queryFn: () => Promise.resolve(returnData),
4534
});
4635
return {
4736
...status,

src/data/services/lms/hooks/selectors.js

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)