Skip to content

Commit b141277

Browse files
authored
Improve /crates route error handling (#10672)
Previously, this route was showing an unhelpful error message. With this change it is using the regular error screen with a "Try again" button and a slightly friendlier error message.
1 parent 4aa9220 commit b141277

File tree

4 files changed

+59
-3
lines changed

4 files changed

+59
-3
lines changed

app/routes/crates.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@ import Route from '@ember/routing/route';
22
import { inject as service } from '@ember/service';
33

44
export default class CratesRoute extends Route {
5+
@service router;
56
@service store;
67

78
queryParams = {
89
page: { refreshModel: true },
910
sort: { refreshModel: true },
1011
};
1112

12-
model(params) {
13-
return this.store.query('crate', params);
13+
async model(params, transition) {
14+
try {
15+
return await this.store.query('crate', params);
16+
} catch (error) {
17+
let title = `Failed to load crate list`;
18+
let details = error.errors?.[0]?.detail;
19+
return this.router.replaceWith('catch-all', { transition, error, title, details, tryAgain: true });
20+
}
1421
}
1522
}

app/templates/catch-all.hbs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
<h1 local-class="title" data-test-title>{{or @model.title "Page not found"}}</h1>
66

7+
{{#if @model.details}}
8+
<p local-class="details" data-test-details>{{@model.details}}</p>
9+
{{/if}}
10+
711
{{#if @model.loginNeeded}}
812
<button
913
type="button"

e2e/acceptance/crates.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect, test } from '@/e2e/helper';
22
import { loadFixtures } from '@crates-io/msw/fixtures';
3+
import { http, HttpResponse } from 'msw';
34

45
test.describe('Acceptance | crates page', { tag: '@acceptance' }, () => {
56
// should match the default set in the crates controller
@@ -79,4 +80,25 @@ test.describe('Acceptance | crates page', { tag: '@acceptance' }, () => {
7980
await page.goto('/crates');
8081
await expect(page.locator('[data-test-crate-row="0"] [data-test-recent-downloads]')).toHaveText('Recent: 2,000');
8182
});
83+
84+
test('shows error message screen', async ({ page, msw }) => {
85+
loadFixtures(msw.db);
86+
87+
let detail =
88+
'Page 1 is unavailable for performance reasons. Please take a look at https://crates.io/data-access for alternatives.';
89+
let error = HttpResponse.json({ errors: [{ detail }] }, { status: 400 });
90+
await msw.worker.use(http.get('/api/v1/crates', () => error));
91+
92+
await page.goto('/crates');
93+
await expect(page.locator('[data-test-404-page]')).toBeVisible();
94+
await expect(page.locator('[data-test-title]')).toHaveText('Failed to load crate list');
95+
await expect(page.locator('[data-test-details]')).toHaveText(detail);
96+
await expect(page.locator('[data-test-try-again]')).toBeVisible();
97+
await expect(page.locator('[data-test-go-back]')).not.toBeVisible();
98+
99+
await msw.worker.resetHandlers();
100+
await page.click('[data-test-try-again]');
101+
await expect(page.locator('[data-test-404-page]')).not.toBeVisible();
102+
await expect(page.locator('[data-test-crate-row]')).toHaveCount(23);
103+
});
82104
});

tests/acceptance/crates-test.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { click, currentURL, visit } from '@ember/test-helpers';
1+
import { click, currentURL } from '@ember/test-helpers';
22
import { module, test } from 'qunit';
33

44
import { loadFixtures } from '@crates-io/msw/fixtures.js';
55
import percySnapshot from '@percy/ember';
66
import a11yAudit from 'ember-a11y-testing/test-support/audit';
77
import { getPageTitle } from 'ember-page-title/test-support';
8+
import { http, HttpResponse } from 'msw';
89

910
import { setupApplicationTest } from 'crates-io/tests/helpers';
1011

1112
import axeConfig from '../axe-config';
13+
import { visit } from '../helpers/visit-ignoring-abort';
1214

1315
module('Acceptance | crates page', function (hooks) {
1416
setupApplicationTest(hooks, { msw: true });
@@ -92,4 +94,25 @@ module('Acceptance | crates page', function (hooks) {
9294
let formatted = Number(2000).toLocaleString();
9395
assert.dom('[data-test-crate-row="0"] [data-test-recent-downloads]').hasText(`Recent: ${formatted}`);
9496
});
97+
98+
test('shows error message screen', async function (assert) {
99+
loadFixtures(this.db);
100+
101+
let detail =
102+
'Page 1 is unavailable for performance reasons. Please take a look at https://crates.io/data-access for alternatives.';
103+
let error = HttpResponse.json({ errors: [{ detail }] }, { status: 400 });
104+
this.worker.use(http.get('/api/v1/crates', () => error));
105+
106+
await visit('/crates');
107+
assert.dom('[data-test-404-page]').exists();
108+
assert.dom('[data-test-title]').hasText('Failed to load crate list');
109+
assert.dom('[data-test-details]').hasText(detail);
110+
assert.dom('[data-test-try-again]').exists();
111+
assert.dom('[data-test-go-back]').doesNotExist();
112+
113+
this.worker.resetHandlers();
114+
await click('[data-test-try-again]');
115+
assert.dom('[data-test-404-page]').doesNotExist();
116+
assert.dom('[data-test-crate-row]').exists({ count: 23 });
117+
});
95118
});

0 commit comments

Comments
 (0)