Skip to content

Commit 5c362f6

Browse files
DanielRyanSmithDanielRyanSmith
andauthored
Add tabbed mobile functionality (#1445)
* Add tabbed mobile functionality * code cleanup * add new tabbed panel component * update async function to properly await * update pwtests * add tests for tabbed panel * pw snapshots * changes suggested by @jcscottiii and pw tests * refactoring suggested by @jcscottiii * fix node test * small pwtest change * changes suggested by @jcscottiii --------- Co-authored-by: DanielRyanSmith <danielrsmith@google.com>
1 parent dd93b71 commit 5c362f6

21 files changed

+837
-206
lines changed

e2e/tests/feature-page.spec.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ test('matches the screenshot', async ({page}) => {
2525
await page.goto('http://localhost:5555/features/odit64');
2626

2727
// Wait for the chart container to exist
28-
await page.waitForSelector('#feature-wpt-implementation-progress-complete');
28+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
2929

3030
// Wait specifically for the "Baseline since" text
3131
await page.waitForSelector('sl-card.wptScore .avail >> text=Baseline since');
@@ -36,13 +36,13 @@ test('matches the screenshot', async ({page}) => {
3636

3737
test('chart width resizes with window', async ({page}) => {
3838
await page.goto('http://localhost:5555/features/odit64');
39-
await page.waitForSelector('#feature-wpt-implementation-progress-complete');
39+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
4040
await page.waitForTimeout(1000);
4141
const narrowWidth = 1000;
4242
const wideWidth = 1200;
4343
const height = 1000;
4444
const chartContainer = page.locator(
45-
'#feature-wpt-implementation-progress-complete',
45+
'#feature-wpt-implementation-progress-0-complete',
4646
);
4747

4848
// Resize to narrow width
@@ -68,9 +68,24 @@ test('chart width resizes with window', async ({page}) => {
6868
await expect(chartContainer).toHaveScreenshot();
6969
});
7070

71+
test('mobile chart displays on click and matches screenshot', async ({
72+
page,
73+
}) => {
74+
await page.goto('http://localhost:5555/features/odit64');
75+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
76+
const mobileTab = page.locator(
77+
'sl-tab#feature-wpt-implementation-progress-tab-mobile',
78+
);
79+
80+
await mobileTab.click();
81+
await page.waitForTimeout(2000);
82+
const pageContainer = page.locator('.page-container');
83+
await expect(pageContainer).toHaveScreenshot();
84+
});
85+
7186
test('date range changes are preserved in the URL', async ({page}) => {
7287
await page.goto('http://localhost:5555/features/odit64');
73-
await page.waitForSelector('#feature-wpt-implementation-progress-complete');
88+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
7489

7590
// Get the current default startDate and endDate from the selectors
7691
// TODO Figure out how to use getByLabel with shoelace and replace page.locator with that.
@@ -100,7 +115,7 @@ test('date range changes are preserved in the URL', async ({page}) => {
100115

101116
// Refresh the page with that URL.
102117
await page.goto(url);
103-
await page.waitForSelector('#feature-wpt-implementation-progress-complete');
118+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
104119

105120
// Check that the startDate and endDate are still there.
106121
const url2 = page.url();
@@ -126,7 +141,7 @@ test('date range changes are preserved in the URL', async ({page}) => {
126141

127142
// Go to that URL.
128143
await page.goto(url3);
129-
await page.waitForSelector('#feature-wpt-implementation-progress-complete');
144+
await page.waitForSelector('#feature-wpt-implementation-progress-0-complete');
130145

131146
// Check that the startDate and endDate selectors are reset to the initial default.
132147
const startDateSelector3 = page.locator('sl-input#start-date');
6.32 KB
Loading
9.01 KB
Loading
6.84 KB
Loading
294 KB
Loading
407 KB
Loading
325 KB
Loading

frontend/src/static/js/components/test/webstatus-feature-usage-chart-panel.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ import '../webstatus-feature-usage-chart-panel.js';
2525
describe('WebstatusFeatureUsageChartPanel', () => {
2626
let el: WebstatusFeatureUsageChartPanel;
2727
let apiClientStub: SinonStubbedInstance<APIClient>;
28-
let fetchAndAggregateDataStub: SinonStub;
28+
let populateDataForChartStub: SinonStub;
2929
const startDate = new Date('2024-01-01');
3030
const endDate = new Date('2024-01-31');
3131

3232
beforeEach(async () => {
3333
apiClientStub = stub(new APIClient(''));
34-
fetchAndAggregateDataStub = stub(
34+
populateDataForChartStub = stub(
3535
WebstatusLineChartPanel.prototype,
36-
'_fetchAndAggregateData',
36+
'_populateDataForChart',
3737
);
3838
el = await fixture<WebstatusFeatureUsageChartPanel>(
3939
testHtml`<webstatus-feature-usage-chart-panel
@@ -47,7 +47,7 @@ describe('WebstatusFeatureUsageChartPanel', () => {
4747
});
4848

4949
afterEach(() => {
50-
fetchAndAggregateDataStub.restore();
50+
populateDataForChartStub.restore();
5151
});
5252

5353
it('renders the card', async () => {
@@ -69,10 +69,10 @@ describe('WebstatusFeatureUsageChartPanel', () => {
6969
expect(el.dataFetchEndDate).to.deep.equal(new Date('2024-01-31'));
7070
});
7171

72-
it('calls _fetchAndAggregateData with correct configurations', async () => {
73-
expect(fetchAndAggregateDataStub).to.have.been.calledOnce;
72+
it('calls _populateDataForChart with correct configurations', async () => {
73+
expect(populateDataForChartStub).to.have.been.calledOnce;
7474
const [fetchFunctionConfigs, additionalSeriesConfigs] =
75-
fetchAndAggregateDataStub.getCall(0).args;
75+
populateDataForChartStub.getCall(0).args;
7676

7777
expect(fetchFunctionConfigs.length).to.equal(1); // Only 1 browser (Chrome)
7878

frontend/src/static/js/components/test/webstatus-feature-wpt-progress-chart-panel.test.ts

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import {
2323
FeatureWPTMetricViewType,
2424
WPTRunMetric,
2525
} from '../../api/client.js';
26-
import {WebstatusLineChartPanel} from '../webstatus-line-chart-panel.js';
2726
import '../webstatus-feature-wpt-progress-chart-panel.js';
27+
import {WebstatusLineChartTabbedPanel} from '../webstatus-line-chart-tabbed-panel.js';
2828

2929
const startDate = new Date('2024-01-01');
3030
const endDate = new Date('2024-01-31');
@@ -46,21 +46,21 @@ async function createFixtureElement(
4646
describe('WebstatusFeatureWPTProgressChartPanel', () => {
4747
let el: WebstatusFeatureWPTProgressChartPanel;
4848
let apiClientStub: SinonStubbedInstance<APIClient>;
49-
let fetchAndAggregateDataStub: SinonStub;
49+
let populateDataForChartByViewStub: SinonStub;
5050

5151
beforeEach(async () => {
5252
apiClientStub = stub(new APIClient(''));
53-
fetchAndAggregateDataStub = stub(
54-
WebstatusLineChartPanel.prototype,
55-
'_fetchAndAggregateData',
53+
populateDataForChartByViewStub = stub(
54+
WebstatusLineChartTabbedPanel.prototype,
55+
'_populateDataForChartByView',
5656
);
5757
el = await createFixtureElement(startDate, endDate, DEFAULT_TEST_VIEW);
5858
el.apiClient = apiClientStub;
5959
await el.updateComplete;
6060
});
6161

6262
afterEach(() => {
63-
fetchAndAggregateDataStub.restore();
63+
populateDataForChartByViewStub.restore();
6464
});
6565

6666
it('renders the card', async () => {
@@ -82,12 +82,13 @@ describe('WebstatusFeatureWPTProgressChartPanel', () => {
8282
expect(el.dataFetchEndDate).to.deep.equal(new Date('2024-01-31'));
8383
});
8484

85-
it('calls _fetchAndAggregateData with correct configurations', async () => {
86-
expect(fetchAndAggregateDataStub).to.have.been.calledOnce;
87-
const [fetchFunctionConfigs, additionalSeriesConfigs] =
88-
fetchAndAggregateDataStub.getCall(0).args;
89-
85+
it('calls _populateDataForChartByView with correct configurations', async () => {
86+
// Call method for both desktop and mobile views.
87+
expect(populateDataForChartByViewStub).to.have.been.calledTwice;
88+
let [fetchFunctionConfigs, dataIndex, additionalSeriesConfigs] =
89+
populateDataForChartByViewStub.getCall(0).args;
9090
expect(fetchFunctionConfigs.length).to.equal(4); // 4 browsers
91+
expect(dataIndex).to.equal(0); // First view index
9192

9293
// Test Chrome configuration
9394
const chromeConfig = fetchFunctionConfigs[0];
@@ -158,10 +159,64 @@ describe('WebstatusFeatureWPTProgressChartPanel', () => {
158159
new Date('2024-01-01T13:00:00.000Z'), // Expecting the rounded timestamp
159160
);
160161
expect(totalConfig.valueExtractor(totalTestDataPoint)).to.equal(15);
162+
163+
[fetchFunctionConfigs, dataIndex, additionalSeriesConfigs] =
164+
populateDataForChartByViewStub.getCall(1).args;
165+
166+
expect(fetchFunctionConfigs.length).to.equal(3); // 3 browsers
167+
expect(dataIndex).to.equal(1); // Second view index
168+
169+
// Test Chrome Android configuration
170+
const chromeAndroidConfig = fetchFunctionConfigs[0];
171+
expect(chromeAndroidConfig.label).to.equal('Chrome Android');
172+
expect(chromeAndroidConfig.fetchFunction).to.be.a('function');
173+
const chromeAndroidTestDataPoint: WPTRunMetric = {
174+
run_timestamp: '2024-01-01T12:34:56.789Z',
175+
total_tests_count: 10,
176+
test_pass_count: 5,
177+
};
178+
expect(
179+
chromeAndroidConfig.timestampExtractor(chromeAndroidTestDataPoint),
180+
).to.deep.equal(
181+
new Date('2024-01-01T13:00:00.000Z'), // Expecting the rounded timestamp
182+
);
183+
expect(
184+
chromeAndroidConfig.valueExtractor(chromeAndroidTestDataPoint),
185+
).to.equal(5);
186+
187+
// Test Firefox Android configuration
188+
const firefoxAndroidConfig = fetchFunctionConfigs[1];
189+
expect(firefoxAndroidConfig.label).to.equal('Firefox Android');
190+
expect(firefoxAndroidConfig.fetchFunction).to.be.a('function');
191+
const firefoxAndroidTestDataPoint: WPTRunMetric = {
192+
run_timestamp: '2024-01-01',
193+
total_tests_count: 12,
194+
test_pass_count: 7,
195+
};
196+
expect(
197+
firefoxAndroidConfig.timestampExtractor(firefoxAndroidTestDataPoint),
198+
).to.deep.equal(new Date('2024-01-01'));
199+
expect(
200+
firefoxAndroidConfig.valueExtractor(firefoxAndroidTestDataPoint),
201+
).to.equal(7);
202+
203+
// Test Safari iOS configuration
204+
const safariIosConfig = fetchFunctionConfigs[2];
205+
expect(safariIosConfig.label).to.equal('Safari iOS');
206+
expect(safariIosConfig.fetchFunction).to.be.a('function');
207+
const safariIosTestDataPoint: WPTRunMetric = {
208+
run_timestamp: '2024-01-01',
209+
total_tests_count: 8,
210+
test_pass_count: 3,
211+
};
212+
expect(
213+
safariIosConfig.timestampExtractor(safariIosTestDataPoint),
214+
).to.deep.equal(new Date('2024-01-01'));
215+
expect(safariIosConfig.valueExtractor(safariIosTestDataPoint)).to.equal(3);
161216
});
162217

163218
it('generates chart options correctly', () => {
164-
const options = el.generateDisplayDataChartOptions();
219+
const options = el.generateDisplayDataChartOptionsByView(0);
165220
// Check colors based on browsers displayed.
166221
// 4 browsers and total.
167222
expect(options.colors).eql([
@@ -180,30 +235,32 @@ describe('WebstatusFeatureWPTProgressChartPanel', () => {
180235

181236
describe('metric view specific tests', () => {
182237
it('generates metric view specific chart options correctly when view=test', async () => {
183-
fetchAndAggregateDataStub.reset();
238+
populateDataForChartByViewStub.reset();
184239
el = await createFixtureElement(startDate, endDate, 'test_counts');
185240
el.apiClient = apiClientStub;
186241
await el.updateComplete;
187-
const options = el.generateDisplayDataChartOptions();
242+
const options = el.generateDisplayDataChartOptionsByView(0);
188243
expect(options.vAxis?.title).to.equal('Number of tests passed');
189-
expect(fetchAndAggregateDataStub).to.have.been.calledOnce;
244+
// Call method for both desktop and mobile views.
245+
expect(populateDataForChartByViewStub).to.have.been.calledTwice;
190246
const additionalSeriesConfigs =
191-
fetchAndAggregateDataStub.getCall(0).args[1];
247+
populateDataForChartByViewStub.getCall(0).args[2];
192248
// Check additional series configurations
193249
expect(additionalSeriesConfigs).to.have.lengthOf(1);
194250
const totalConfig = additionalSeriesConfigs[0];
195251
expect(totalConfig.label).to.equal('Total number of tests');
196252
});
197253
it('generates metric view specific chart options correctly when view=subtest', async () => {
198-
fetchAndAggregateDataStub.reset();
254+
populateDataForChartByViewStub.reset();
199255
el = await createFixtureElement(startDate, endDate, 'subtest_counts');
200256
el.apiClient = apiClientStub;
201257
await el.updateComplete;
202-
const options = el.generateDisplayDataChartOptions();
258+
const options = el.generateDisplayDataChartOptionsByView(0);
203259
expect(options.vAxis?.title).to.equal('Number of subtests passed');
204-
expect(fetchAndAggregateDataStub).to.have.been.calledOnce;
260+
// Call method for both desktop and mobile views.
261+
expect(populateDataForChartByViewStub).to.have.been.calledTwice;
205262
const additionalSeriesConfigs =
206-
fetchAndAggregateDataStub.getCall(0).args[1];
263+
populateDataForChartByViewStub.getCall(0).args[2];
207264
// Check additional series configurations
208265
expect(additionalSeriesConfigs).to.have.lengthOf(1);
209266
const totalConfig = additionalSeriesConfigs[0];

frontend/src/static/js/components/test/webstatus-line-chart-panel.test.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {WebStatusDataObj, WebstatusGChart} from '../webstatus-gchart.js';
2626
import {TemplateResult, html} from 'lit';
2727
import {customElement} from 'lit/decorators.js';
2828
import {createMockIterator, taskUpdateComplete} from './test-helpers.js';
29+
import {BrowsersParameter} from '../../api/client.js';
2930

3031
// Interface for the data used in LineChartMetricData
3132
interface MetricDataPoint {
@@ -34,7 +35,9 @@ interface MetricDataPoint {
3435
}
3536

3637
@customElement('test-line-chart-panel')
37-
class TestLineChartPanel extends WebstatusLineChartPanel {
38+
class TestLineChartPanel extends WebstatusLineChartPanel<BrowsersParameter> {
39+
readonly series: BrowsersParameter[] = [];
40+
3841
resolveTask!: (value: WebStatusDataObj) => void;
3942
rejectTask!: (reason: Error) => void;
4043
resolvePointSelectedTask!: (value: unknown) => void;
@@ -88,7 +91,9 @@ class TestLineChartPanel extends WebstatusLineChartPanel {
8891
return html``;
8992
}
9093

91-
getDisplayDataChartOptionsInput(): {
94+
getDisplayDataChartOptionsInput<BrowsersParameter>(
95+
_browsers: BrowsersParameter[],
96+
): {
9297
seriesColors: Array<string>;
9398
vAxisTitle: string;
9499
} {
@@ -151,14 +156,15 @@ describe('WebstatusLineChartPanel', () => {
151156
},
152157
];
153158

154-
el.setDisplayDataFromMap(metricDataArray);
155-
expect(el.data).to.exist;
156-
expect(el.data!.cols).to.deep.equal([
159+
const formattedMetricData = el.processDisplayDataFromMap(metricDataArray);
160+
expect(formattedMetricData).to.exist;
161+
162+
expect(formattedMetricData.cols).to.deep.equal([
157163
{type: 'date', label: 'Date', role: 'domain'},
158164
{type: 'number', label: 'Metric 1', role: 'data'},
159165
{type: 'number', label: 'Metric 2', role: 'data'},
160166
]);
161-
expect(el.data!.rows).to.deep.equal([
167+
expect(formattedMetricData.rows).to.deep.equal([
162168
[new Date('2024-01-01'), 10, 15], // Values for both metrics on the same date
163169
[new Date('2024-01-02'), 20, 25], // Values for both metrics on the same date
164170
[new Date('2024-01-03'), null, 30], // Metric 1 is null because it has no data for 2024-01-03
@@ -210,7 +216,7 @@ describe('WebstatusLineChartPanel', () => {
210216
expect(errorMessage!.textContent).to.include('Error when loading chart');
211217
});
212218

213-
describe('_fetchAndAggregateData', () => {
219+
describe('_populateDataForChart', () => {
214220
it('fetches data and applies additional series calculators', async () => {
215221
const fetchFunctionConfigs: FetchFunctionConfig<MetricDataPoint>[] = [
216222
{
@@ -248,7 +254,7 @@ describe('WebstatusLineChartPanel', () => {
248254
},
249255
];
250256

251-
await el._fetchAndAggregateData(
257+
await el._populateDataForChart(
252258
fetchFunctionConfigs,
253259
additionalSeriesConfigs,
254260
);
@@ -283,7 +289,7 @@ describe('WebstatusLineChartPanel', () => {
283289
const startingListener = oneEvent(el, 'data-fetch-starting');
284290
const completeListener = oneEvent(el, 'data-fetch-complete');
285291

286-
await el._fetchAndAggregateData(fetchFunctionConfigs);
292+
await el._populateDataForChart(fetchFunctionConfigs);
287293

288294
await startingListener;
289295
const {detail} = await completeListener;

0 commit comments

Comments
 (0)