richie-education 3.5.2-dev6 → 3.5.2-dev8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/api/lms/dummy.ts +1 -0
- package/js/api/lms/openedx-fonzie-keycloak.spec.ts +7 -10
- package/js/api/lms/openedx-fonzie-keycloak.ts +24 -21
- package/js/components/SaleTunnel/index.spec.tsx +30 -0
- package/js/widgets/Dashboard/components/DashboardItem/Order/OrderWithdrawalModal/index.spec.tsx +8 -2
- package/package.json +1 -1
package/js/api/lms/dummy.ts
CHANGED
|
@@ -31,19 +31,16 @@ describe('Fonzie Keycloak API', () => {
|
|
|
31
31
|
jest.clearAllMocks();
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('
|
|
34
|
+
it('reads the email and full name from the access token claims', async () => {
|
|
35
|
+
// JWT payload: { email: 'john.doe@example.com', full_name: 'John Doe' }
|
|
36
|
+
const accessToken =
|
|
37
|
+
'header.eyJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIiwiZnVsbF9uYW1lIjoiSm9obiBEb2UifQ.signature';
|
|
35
38
|
const user = {
|
|
36
39
|
username: 'test-richie-ncl',
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
const keycloakAccount = {
|
|
40
|
-
firstName: 'John',
|
|
41
|
-
lastName: 'Doe',
|
|
42
|
-
email: 'john.doe@example.com',
|
|
40
|
+
access_token: accessToken,
|
|
43
41
|
};
|
|
44
42
|
|
|
45
43
|
fetchMock.get('https://demo.endpoint.api/api/v1.0/user/me', user);
|
|
46
|
-
fetchMock.get('https://keycloak.test/auth/realms/richie-realm/account/', keycloakAccount);
|
|
47
44
|
|
|
48
45
|
const api = FonzieKeycloakAPIInterface(configuration);
|
|
49
46
|
await expect(api.user.me()).resolves.toEqual({
|
|
@@ -53,14 +50,14 @@ describe('Fonzie Keycloak API', () => {
|
|
|
53
50
|
});
|
|
54
51
|
});
|
|
55
52
|
|
|
56
|
-
it('
|
|
53
|
+
it('does not fail when the access token has no usable claims', async () => {
|
|
57
54
|
const user = {
|
|
58
55
|
username: 'test-richie-ncl',
|
|
59
56
|
full_name: 'n c',
|
|
57
|
+
access_token: 'not-a-jwt',
|
|
60
58
|
};
|
|
61
59
|
|
|
62
60
|
fetchMock.get('https://demo.endpoint.api/api/v1.0/user/me', user);
|
|
63
|
-
fetchMock.get('https://keycloak.test/auth/realms/richie-realm/account/', 500);
|
|
64
61
|
|
|
65
62
|
const api = FonzieKeycloakAPIInterface(configuration);
|
|
66
63
|
await expect(api.user.me()).resolves.toEqual(user);
|
|
@@ -8,8 +8,25 @@ import { OpenEdxApiProfile } from 'types/openEdx';
|
|
|
8
8
|
import { checkStatus } from 'api/utils';
|
|
9
9
|
import { OpenEdxFullNameFormValues } from 'components/OpenEdxFullNameForm';
|
|
10
10
|
import { location } from 'utils/indirection/window';
|
|
11
|
+
import { base64Decode } from 'utils/base64Parser';
|
|
12
|
+
import { Maybe } from 'types/utils';
|
|
11
13
|
import OpenEdxHawthornApiInterface from './openedx-hawthorn';
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Extract claims from the JWT issued by Fonzie. The `user/me` route does not expose
|
|
17
|
+
* the email nor an up to date full name, but the token it returns always carries them.
|
|
18
|
+
*/
|
|
19
|
+
const getTokenClaims = (token: Maybe<string>): Maybe<{ email?: string; full_name?: string }> => {
|
|
20
|
+
if (!token) return undefined;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const payload = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
24
|
+
return JSON.parse(base64Decode(payload));
|
|
25
|
+
} catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
*
|
|
15
32
|
* OpenEdX completed by Fonzie API Implementation
|
|
@@ -46,27 +63,13 @@ const API = (APIConf: AuthenticationBackend): APILms => {
|
|
|
46
63
|
me: async () => {
|
|
47
64
|
const user = await ApiInterface.user.me();
|
|
48
65
|
if (!user) return null;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}).then((res) => {
|
|
57
|
-
if (!res.ok) throw new Error(`Keycloak account fetch failed: ${res.status}`);
|
|
58
|
-
return res.json();
|
|
59
|
-
});
|
|
60
|
-
return {
|
|
61
|
-
...user,
|
|
62
|
-
full_name:
|
|
63
|
-
[keycloakAccount.firstName, keycloakAccount.lastName].filter(Boolean).join(' ') ||
|
|
64
|
-
user.full_name,
|
|
65
|
-
email: keycloakAccount.email || user.email,
|
|
66
|
-
};
|
|
67
|
-
} catch {
|
|
68
|
-
return user;
|
|
69
|
-
}
|
|
66
|
+
|
|
67
|
+
const claims = getTokenClaims(user.access_token);
|
|
68
|
+
return {
|
|
69
|
+
...user,
|
|
70
|
+
full_name: user.full_name || claims?.full_name,
|
|
71
|
+
email: user.email ?? claims?.email,
|
|
72
|
+
};
|
|
70
73
|
},
|
|
71
74
|
login: () => {
|
|
72
75
|
const next = encodeURIComponent(location.href);
|
|
@@ -706,6 +706,36 @@ describe.each([
|
|
|
706
706
|
screen.getByTestId('walkthrough-banner');
|
|
707
707
|
});
|
|
708
708
|
|
|
709
|
+
it('should render the account name and email from the OpenEdx profile', async () => {
|
|
710
|
+
const product = ProductFactory().one();
|
|
711
|
+
const paymentPlan = PaymentPlanFactory().one();
|
|
712
|
+
fetchMock
|
|
713
|
+
.get(
|
|
714
|
+
`https://joanie.endpoint/api/v1.0/orders/?${queryString.stringify(getFetchOrderQueryParams(product))}`,
|
|
715
|
+
[],
|
|
716
|
+
)
|
|
717
|
+
.get(
|
|
718
|
+
`https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/payment-plan/`,
|
|
719
|
+
paymentPlan,
|
|
720
|
+
)
|
|
721
|
+
.get(
|
|
722
|
+
`https://joanie.endpoint/api/v1.0/courses/${course.code}/products/${product.id}/deep-link/`,
|
|
723
|
+
{},
|
|
724
|
+
);
|
|
725
|
+
|
|
726
|
+
render(<Wrapper product={product} isWithdrawable={true} paymentPlan={paymentPlan} />, {
|
|
727
|
+
queryOptions: { client: createTestQueryClient({ user: richieUser }) },
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
screen.getByRole('heading', { level: 4, name: 'Account email' });
|
|
731
|
+
|
|
732
|
+
await screen.findByText(openApiEdxProfile.email);
|
|
733
|
+
|
|
734
|
+
screen.getByText(
|
|
735
|
+
'This email will be used to send you confirmation mails, it is the one you created your account with.',
|
|
736
|
+
);
|
|
737
|
+
});
|
|
738
|
+
|
|
709
739
|
it('should show a checkbox to waive withdrawal right if the product is not withdrawable', async () => {
|
|
710
740
|
const product = ProductFactory().one();
|
|
711
741
|
const paymentPlan = PaymentPlanFactory().one();
|
package/js/widgets/Dashboard/components/DashboardItem/Order/OrderWithdrawalModal/index.spec.tsx
CHANGED
|
@@ -32,7 +32,10 @@ jest.mock('@openfun/cunningham-react', () => ({
|
|
|
32
32
|
describe('<OrderWithdrawalModal/>', () => {
|
|
33
33
|
setupJoanieSession();
|
|
34
34
|
const user = UserFactory().one();
|
|
35
|
-
const renderModal = (
|
|
35
|
+
const renderModal = (
|
|
36
|
+
props: Partial<React.ComponentProps<typeof OrderWithdrawalModal>>,
|
|
37
|
+
sessionUser = user,
|
|
38
|
+
) =>
|
|
36
39
|
render(
|
|
37
40
|
<OrderWithdrawalModal
|
|
38
41
|
isOpen
|
|
@@ -42,7 +45,7 @@ describe('<OrderWithdrawalModal/>', () => {
|
|
|
42
45
|
reference="COURSE-CODE"
|
|
43
46
|
{...props}
|
|
44
47
|
/>,
|
|
45
|
-
{ queryOptions: { client: createTestQueryClient({ user }) } },
|
|
48
|
+
{ queryOptions: { client: createTestQueryClient({ user: sessionUser }) } },
|
|
46
49
|
);
|
|
47
50
|
|
|
48
51
|
it('should display order and user information, without the account update link for a non-keycloak backend', () => {
|
|
@@ -53,8 +56,11 @@ describe('<OrderWithdrawalModal/>', () => {
|
|
|
53
56
|
expect(
|
|
54
57
|
screen.getByText('You wish to cancel your subscription to', { exact: false }),
|
|
55
58
|
).toBeInTheDocument();
|
|
59
|
+
expect(screen.getByText('Account name')).toBeInTheDocument();
|
|
56
60
|
expect(screen.getByText(user.full_name!)).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('Account email')).toBeInTheDocument();
|
|
57
62
|
expect(screen.getByText(user.email!)).toBeInTheDocument();
|
|
63
|
+
expect(screen.getByText('Order reference')).toBeInTheDocument();
|
|
58
64
|
expect(screen.getByText(order.id)).toBeInTheDocument();
|
|
59
65
|
expect(
|
|
60
66
|
screen.queryByRole('link', { name: 'please update your account' }),
|