Skip to content

Commit 23b904a

Browse files
committed
frontend: Add PristineParamsService
This makes the support link in the footer testable and eliminates the need to manually update query params when new ones are added.
1 parent e85a97d commit 23b904a

File tree

5 files changed

+168
-4
lines changed

5 files changed

+168
-4
lines changed

app/components/footer.hbs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@
1414
<ul role="list">
1515
<li><a href="https://doc.rust-lang.org/cargo/">The Cargo Book</a></li>
1616
<li><a href="mailto:[email protected]">Email Support</a></li>
17-
<li><LinkTo @route="support" @query={{hash
18-
inquire=null
19-
crate=null
20-
}}>Support</LinkTo></li>
17+
<li><LinkTo @route="support" @query={{this.pristineSupportQuery}}>Support</LinkTo></li>
2118
<li><a href="https://status.crates.io/">System Status</a></li>
2219
<li><a href="https://github.com/rust-lang/crates.io/issues/new/choose">Report a bug</a></li>
2320
</ul>

app/components/footer.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { inject as service } from '@ember/service';
2+
import Component from '@glimmer/component';
3+
4+
export default class Footer extends Component {
5+
@service pristineQuery;
6+
7+
get pristineSupportQuery() {
8+
let params = this.pristineQuery.paramsFor('support');
9+
return params;
10+
}
11+
}

app/services/pristine-query.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { getOwner } from '@ember/owner';
2+
import Service from '@ember/service';
3+
4+
export default class PristineParamsService extends Service {
5+
paramsFor(route) {
6+
let params = getOwner(this).lookup(`controller:${route}`)?.queryParams || [];
7+
return Object.fromEntries(params.map(k => [k, null]));
8+
}
9+
}

e2e/routes/support.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { test, expect } from '@/e2e/helper';
2+
3+
test.describe('Route | support', { tag: '@routes' }, () => {
4+
test('should not retain query params when exiting and then returning', async ({ page }) => {
5+
await page.goto('/support?inquire=crate-violation');
6+
await expect(page).toHaveURL('/support?inquire=crate-violation');
7+
let section = page.getByTestId('support-main-content').locator('section');
8+
await expect(section).toHaveCount(1);
9+
await expect(section).toHaveAttribute('data-test-id', 'crate-violation-section');
10+
11+
// back to index
12+
await page.locator('header [href="/"]').click();
13+
await expect(page).toHaveURL('/');
14+
let link = page.locator('footer').getByRole('link', { name: 'Support', exact: true });
15+
await expect(link).toBeVisible();
16+
await expect(link).toHaveAttribute('href', '/support');
17+
18+
// goto support
19+
await link.click();
20+
await expect(page).toHaveURL('/support');
21+
section = page.getByTestId('support-main-content').locator('section');
22+
await expect(section).toHaveCount(1);
23+
await expect(section).toHaveAttribute('data-test-id', 'inquire-list-section');
24+
await page.getByTestId('link-crate-violation').click();
25+
await expect(page).toHaveURL('/support?inquire=crate-violation');
26+
});
27+
28+
test('LinkTo support must overwirte query', async ({ page, ember }) => {
29+
await ember.addHook(async owner => {
30+
const Service = require('@ember/service').default;
31+
// query params of LinkTo support's in footer will not be cleared
32+
class MockService extends Service {
33+
paramsFor() {
34+
return {};
35+
}
36+
}
37+
owner.register('service:pristine-query', MockService);
38+
});
39+
await page.goto('/support?inquire=crate-violation');
40+
await expect(page).toHaveURL('/support?inquire=crate-violation');
41+
let section = page.getByTestId('support-main-content').locator('section');
42+
await expect(section).toHaveCount(1);
43+
await expect(section).toHaveAttribute('data-test-id', 'crate-violation-section');
44+
// without overwriting, link in footer will contain the query params in support route
45+
let link = page.locator('footer').getByRole('link', { name: 'Support', exact: true });
46+
await expect(link).not.toHaveAttribute('href', '/support');
47+
await expect(link).toHaveAttribute('href', '/support?inquire=crate-violation');
48+
49+
// back to index
50+
await page.locator('header [href="/"]').click();
51+
await expect(page).toHaveURL('/');
52+
link = page.locator('footer').getByRole('link', { name: 'Support', exact: true });
53+
await expect(link).toBeVisible();
54+
await expect(link).toHaveAttribute('href', '/support');
55+
});
56+
});

tests/routes/support-test.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { click, currentURL } from '@ember/test-helpers';
2+
import { module, test } from 'qunit';
3+
4+
import Service from '@ember/service';
5+
6+
import { setupApplicationTest } from 'crates-io/tests/helpers';
7+
8+
import { visit } from '../helpers/visit-ignoring-abort';
9+
10+
module('Route | support', function (hooks) {
11+
setupApplicationTest(hooks);
12+
13+
test('should not retain query params when exiting and then returning', async function (assert) {
14+
await visit('/support?inquire=crate-violation');
15+
assert.strictEqual(currentURL(), '/support?inquire=crate-violation');
16+
assert
17+
.dom('[data-test-id="support-main-content"] section')
18+
.exists({ count: 1 })
19+
.hasAttribute('data-test-id', 'crate-violation-section');
20+
21+
// back to index
22+
await click('header [href="/"]');
23+
assert.strictEqual(currentURL(), '/');
24+
assert.dom('footer [href="/support"]').exists();
25+
26+
// goto support
27+
await click('footer [href="/support"]');
28+
assert.strictEqual(currentURL(), '/support');
29+
assert
30+
.dom('[data-test-id="support-main-content"] section')
31+
.exists({ count: 1 })
32+
.hasAttribute('data-test-id', 'inquire-list-section');
33+
await click('[data-test-id="link-crate-violation"]');
34+
assert.strictEqual(currentURL(), '/support?inquire=crate-violation');
35+
});
36+
37+
test('LinkTo support must overwite query', async function (assert) {
38+
// query params of LinkTo support's in footer will not be cleared
39+
class MockService extends Service {
40+
paramsFor() {
41+
return {};
42+
}
43+
}
44+
this.owner.register('service:pristine-query', MockService);
45+
46+
await visit('/support?inquire=crate-violation');
47+
assert.strictEqual(currentURL(), '/support?inquire=crate-violation');
48+
assert
49+
.dom('[data-test-id="support-main-content"] section')
50+
.exists({ count: 1 })
51+
.hasAttribute('data-test-id', 'crate-violation-section');
52+
// without overwriting, link in footer will contain the query params in support route
53+
assert.dom('footer [href^="/support"]').doesNotMatchSelector('[href="/support"]');
54+
assert.dom('footer [href^="/support"]').hasAttribute('href', '/support?inquire=crate-violation');
55+
56+
// back to index
57+
await click('header [href="/"]');
58+
assert.strictEqual(currentURL(), '/');
59+
assert.dom('footer [href^="/support"]').hasAttribute('href', '/support');
60+
});
61+
62+
test('must reset query when existing', async function (assert) {
63+
const route = this.owner.lookup('route:support');
64+
const originResetController = route.resetController;
65+
// query params of LinkTo support's in footer will not be cleared
66+
class MockService extends Service {
67+
paramsFor() {
68+
return {};
69+
}
70+
}
71+
this.owner.register('service:pristine-query', MockService);
72+
// exiting support will not reset query
73+
route.resetController = () => {};
74+
75+
await visit('/support?inquire=crate-violation');
76+
assert.strictEqual(currentURL(), '/support?inquire=crate-violation');
77+
assert
78+
.dom('[data-test-id="support-main-content"] section')
79+
.exists({ count: 1 })
80+
.hasAttribute('data-test-id', 'crate-violation-section');
81+
82+
// back to index
83+
await click('header [href="/"]');
84+
assert.strictEqual(currentURL(), '/');
85+
// without resetController to reset, link in footer will contain the query params in other route
86+
assert.dom('footer [href^="/support"]').doesNotMatchSelector('[href="/support"]');
87+
assert.dom('footer [href^="/support"]').hasAttribute('href', '/support?inquire=crate-violation');
88+
89+
route.resetController = originResetController;
90+
});
91+
});

0 commit comments

Comments
 (0)