Skip to content

Commit 21cafae

Browse files
committed
Claude: mocking window.location better and managing nextParam in a more testable way
1 parent 1c3ce5b commit 21cafae

2 files changed

Lines changed: 44 additions & 26 deletions

File tree

contentcuration/contentcuration/frontend/accounts/pages/AccountsMain.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@
165165
showPrivacyPolicy() {
166166
this.$router.push({ query: { showPolicy: policies.PRIVACY } });
167167
},
168+
navigate(path) {
169+
// Extracted for easier testing
170+
window.location.assign(path);
171+
},
168172
submit() {
169173
if (this.$refs.form.validate()) {
170174
this.busy = true;
@@ -176,7 +180,8 @@
176180
.then(() => {
177181
this.loginFailedOffline = false;
178182
this.loginFailed = false;
179-
window.location.assign(this.nextParam || window.Urls.channels());
183+
const path = this.nextParam || window.Urls.channels();
184+
this.navigate(path);
180185
})
181186
.catch(err => {
182187
this.busy = false;

contentcuration/contentcuration/frontend/accounts/pages/__tests__/accountsMain.spec.js

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, screen, waitFor } from '@testing-library/vue';
1+
import { render, screen, waitFor, within } from '@testing-library/vue';
22
import userEvent from '@testing-library/user-event';
33
import VueRouter from 'vue-router';
44
import AccountsMain from '../AccountsMain.vue';
@@ -28,31 +28,43 @@ const createRouter = () => {
2828
function makeWrapper({ loginMock = jest.fn(), online = true, nextParam = null } = {}) {
2929
const router = createRouter();
3030

31-
delete window.location;
32-
window.location = {
33-
...originalLocation,
34-
search: nextParam ? `?next=${nextParam}` : '',
35-
assign: jest.fn(),
36-
toString: jest.fn(),
31+
// Mock window.location.search using JSDOM's history API
32+
const searchString = nextParam ? `?next=${nextParam}` : '';
33+
window.history.pushState({}, '', `/${searchString}`);
34+
35+
// Create a spy for navigate before rendering
36+
const navigateSpy = jest.fn();
37+
const OriginalAccountsMain = AccountsMain;
38+
39+
// Patch the component to use our spy
40+
const PatchedAccountsMain = {
41+
...OriginalAccountsMain,
42+
methods: {
43+
...OriginalAccountsMain.methods,
44+
navigate: navigateSpy,
45+
},
3746
};
3847

39-
return {
40-
...render(AccountsMain, {
41-
routes: router,
42-
stubs: ['PolicyModals'],
43-
mocks: {
44-
$store: {
45-
state: {
46-
connection: {
47-
online,
48-
},
48+
const wrapper = render(PatchedAccountsMain, {
49+
routes: router,
50+
stubs: ['PolicyModals'],
51+
mocks: {
52+
$store: {
53+
state: {
54+
connection: {
55+
online,
4956
},
50-
dispatch: loginMock,
5157
},
58+
dispatch: loginMock,
5259
},
53-
}),
60+
},
61+
});
62+
63+
return {
64+
...wrapper,
5465
router,
5566
loginMock,
67+
navigateSpy,
5668
};
5769
}
5870

@@ -61,11 +73,12 @@ describe('AccountsMain', () => {
6173

6274
beforeEach(() => {
6375
user = userEvent.setup();
64-
jest.clearAllMocks();
6576
});
6677

6778
afterEach(() => {
68-
window.location = originalLocation;
79+
// Reset history
80+
window.history.pushState({}, '', '/');
81+
jest.restoreAllMocks();
6982
});
7083

7184
it('should render sign-in form with email, password fields and sign in button', () => {
@@ -105,15 +118,15 @@ describe('AccountsMain', () => {
105118

106119
it('should redirect to channels page after successful login', async () => {
107120
const loginMock = jest.fn().mockResolvedValue();
108-
makeWrapper({ loginMock });
121+
const { navigateSpy } = makeWrapper({ loginMock });
109122

110123
await user.type(screen.getByLabelText(/email/i), 'test@test.com');
111124
await user.type(screen.getByLabelText(/password/i), 'testpassword');
112125
await user.click(screen.getByRole('button', { name: /sign in/i }));
113126

114127
// User is redirected to channels page
115128
await waitFor(() => {
116-
expect(window.location.assign).toHaveBeenCalledWith('/channels/');
129+
expect(navigateSpy).toHaveBeenCalledWith('/channels/');
117130
});
118131
});
119132

@@ -126,15 +139,15 @@ describe('AccountsMain', () => {
126139
it('should redirect to next URL when provided after successful login', async () => {
127140
const loginMock = jest.fn().mockResolvedValue();
128141
const nextUrl = '/protected-page/';
129-
makeWrapper({ loginMock, nextParam: nextUrl });
142+
const { navigateSpy } = makeWrapper({ loginMock, nextParam: nextUrl });
130143

131144
await user.type(screen.getByLabelText(/email/i), 'test@test.com');
132145
await user.type(screen.getByLabelText(/password/i), 'testpassword');
133146
await user.click(screen.getByRole('button', { name: /sign in/i }));
134147

135148
// User is redirected to next URL
136149
await waitFor(() => {
137-
expect(window.location.assign).toHaveBeenCalledWith(nextUrl);
150+
expect(navigateSpy).toHaveBeenCalledWith(nextUrl);
138151
});
139152
});
140153

0 commit comments

Comments
 (0)