Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,82 @@ describe('webstatus-feature-page', () => {
});
});

describe('renderBrowserAvailability', () => {
let element: FeaturePage;
let hostElement: HTMLDivElement;

beforeEach(async () => {
element = await fixture(
html`<webstatus-feature-page
.location=${location}
></webstatus-feature-page>`,
);
hostElement = document.createElement('div');
});

it('renders an explicit available status', async () => {
const actual = element.renderBrowserAvailability({status: 'available'});
render(actual, hostElement);
const host = await fixture(hostElement);

expect(host.textContent?.trim()).to.equal('Available');
expect(host.querySelector('.availability')).to.have.class('available');
expect(host.querySelector('img')?.getAttribute('src')).to.equal(
'/public/img/check.svg',
);
});

it('renders an explicit unavailable status when no implementation exists', async () => {
const actual = element.renderBrowserAvailability();
render(actual, hostElement);
const host = await fixture(hostElement);

expect(host.textContent?.trim()).to.equal('Not available');
expect(host.querySelector('.availability')).to.have.class('unavailable');
expect(host.querySelector('img')?.getAttribute('src')).to.equal(
'/public/img/cross.svg',
);
});
});

describe('renderOneWPTCard', () => {
let element: FeaturePage;
let hostElement: HTMLDivElement;

beforeEach(async () => {
element = await fixture(
html`<webstatus-feature-page
.location=${location}
></webstatus-feature-page>`,
);
element.endDate = new Date('2025-01-01');
hostElement = document.createElement('div');
});

it('does not confuse available features without WPT scores with unavailable features', async () => {
element.feature = {
feature_id: 'id',
name: 'name',
browser_implementations: {
safari_ios: {status: 'available', date: '2024-01-01'},
},
};

const actual = element.renderOneWPTCard('safari_ios', 'safari_32x32.png');
render(actual, hostElement);
const host = await fixture(hostElement);

expect(host.querySelector('.availability')?.textContent?.trim()).to.equal(
'Available',
);
expect(host.querySelector('.score')?.textContent?.trim()).to.equal(
'No score',
);
expect(host.textContent).to.contain('Available since 2024-01-01');
expect(host.textContent).to.contain('WPT score');
});
});

describe('renderDeveloperSignal', () => {
let element: FeaturePage;
let hostElement: HTMLDivElement;
Expand Down
47 changes: 45 additions & 2 deletions frontend/src/static/js/components/webstatus-feature-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,27 @@ export class FeaturePage extends BaseChartsPage {
font-size: 150%;
white-space: nowrap;
}
.wptScore .availability {
display: flex;
align-items: center;
gap: var(--content-padding-quarter);
font-weight: 600;
}
.wptScore .availability.available {
color: var(--color-green-fg);
}
.wptScore .availability.unavailable {
color: var(--color-red-fg);
}
.wptScore .availability img {
width: 20px;
height: 20px;
flex-shrink: 0;
}
.wptScore .score-label {
color: var(--unimportant-text-color);
font-size: 85%;
}
.wptScore.baseline .score {
font-size: 150%;
white-space: wrap;
Expand Down Expand Up @@ -713,23 +734,45 @@ export class FeaturePage extends BaseChartsPage {
`;
}

renderBrowserAvailability(
browserImpl?: components['schemas']['BrowserImplementation'],
): TemplateResult {
const available = browserImpl?.status === 'available';
const status = available ? 'available' : 'unavailable';
const label = available ? 'Available' : 'Not available';
const icon = available ? 'check.svg' : 'cross.svg';

return html`
<div class="availability ${status}">
<img src="/public/img/${icon}" alt="" aria-hidden="true" />
<span>${label}</span>
</div>
`;
}

renderOneWPTCard(
browser: components['parameters']['browserPathParam'],
icon: string,
): TemplateResult {
const browserImpl = this.feature?.browser_implementations?.[browser];
const scorePart = this.feature
? renderBrowserQuality(
this.feature,
{search: ''},
{browser: browser, fallbackText: 'N/A'},
{
browser: browser,
fallbackText:
browserImpl?.status === 'available' ? 'No score' : 'N/A',
},
)
: html`<sl-skeleton effect="sheen"></sl-skeleton>`;
const browserImpl = this.feature?.browser_implementations?.[browser];

return html`
<sl-card class="halign-stretch wptScore">
<img height="32" src="/public/img/${icon}" class="icon" />
<div>${BROWSER_ID_TO_LABEL[browser]}</div>
${this.renderBrowserAvailability(browserImpl)}
<div class="score-label">WPT score</div>
<div class="score">${scorePart}</div>
${this.renderBrowserImpl(browserImpl)}
</sl-card>
Expand Down