Skip to content
Merged
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
6 changes: 3 additions & 3 deletions js/views/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function configBasename(url) {
return (url.split('/').pop() || 'config.yaml').replace(/[^\w.\-]/g, '_');
}
function downloadText(text, filename) {
const blob = new Blob([text], { type: 'text/yaml' });
const blob = new Blob([text], { type: 'application/yaml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = filename;
Expand Down Expand Up @@ -66,10 +66,10 @@ export function renderDevice(el, device) {
${segHtml('channel-seg', 'Channel', channels, channel, 'channel')}
<div id="variant-slot"></div>
</div>
${channels.length < 2 && Object.keys(device.firmware[channel]).length < 2
? '<p style="color:var(--dim);margin:0 0 4px;">One firmware for this device — nothing to choose here.</p>' : ''}
<div id="release-slot"></div>
<div id="config-slot"></div>
${channels.length < 2 && Object.keys(device.firmware[channel]).length < 2
? '<p style="color:var(--dim);margin:0;">One firmware for this device — nothing to choose here.</p>' : ''}
</section>

<section class="step">
Expand Down
22 changes: 21 additions & 1 deletion tests/installer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ test('step 3 explains taking control in the ESPHome Dashboard', async ({ page })

function blobFromRaw(raw) {
const m = raw.match(/^https:\/\/raw\.githubusercontent\.com\/([^/]+)\/([^/]+)\/([^/]+)\/(.+)$/);
return `https://github.com/${m[1]}/${m[2]}/blob/${m[3]}/${m[4]}`;
// Mirror the app's rawToBlob fallback: on a non-match, return the raw URL rather
// than throwing on m[1], so a future off-pattern URL fails as a clean assertion.
return m ? `https://github.com/${m[1]}/${m[2]}/blob/${m[3]}/${m[4]}` : raw;
}
function defaultSel(d) {
const channels = Object.keys(d.firmware);
Expand Down Expand Up @@ -265,3 +267,21 @@ test('device config: no section when the device has no config', async ({ page })
await page.goto(`/#/${d.id}`);
await expect(page.locator('.config')).toHaveCount(0);
});

test('single-firmware devices show the "nothing to choose" note above the release/config sections', async ({ page }) => {
const d = registry.devices.find((x) => {
const chans = Object.keys(x.firmware);
return chans.length === 1 && Object.keys(x.firmware[chans[0]]).length === 1;
});
test.skip(!d, 'no single-firmware device in registry');
await page.goto(`/#/${d.id}`);
const step = page.locator('.device-page .step').first();
await expect(step.getByText('nothing to choose here')).toBeVisible();
// The note must render up under the picker, above the "What's new" and reflash sections.
const noteBeforeRelease = await step.evaluate((el) => {
const note = [...el.querySelectorAll('p')].find((p) => p.textContent.includes('nothing to choose'));
const rel = el.querySelector('#release-slot');
return !!(note && rel && (note.compareDocumentPosition(rel) & Node.DOCUMENT_POSITION_FOLLOWING));
});
expect(noteBeforeRelease).toBe(true);
});
Loading