Skip to content

Commit

Permalink
Add playwright e2e tests for solid-start
Browse files Browse the repository at this point in the history
  • Loading branch information
simonihmig committed Dec 21, 2024
1 parent 241df3c commit a82ee1e
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 2 deletions.
6 changes: 6 additions & 0 deletions apps/solid-start/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ gitignore
# System Files
.DS_Store
Thumbs.db

# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
5 changes: 4 additions & 1 deletion apps/solid-start/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start",
"version": "vinxi version"
"version": "vinxi version",
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"dependencies": {
"@playwright/test": "1.49.1",
"@responsive-image/cdn": "workspace:*",
"@responsive-image/core": "workspace:*",
"@responsive-image/solid": "workspace:*",
Expand Down
75 changes: 75 additions & 0 deletions apps/solid-start/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { defineConfig, devices } from '@playwright/test';

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './tests',
snapshotPathTemplate:
'{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: 'http://localhost:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',

testIdAttribute: '',
},

/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},

// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },

// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },

/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },

/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],

/* Run your local dev server before starting the tests */
webServer: {
// serve the prod build, as the dev build uses vite middleware URLs for images that we don't want in tests
command: 'pnpm build && pnpm start',
url: 'http://localhost:3000',
},
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
206 changes: 206 additions & 0 deletions apps/solid-start/tests/responsive-image.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { test, expect } from '@playwright/test';

const sizes = [640, 750, 828, 1080, 1200, 1920, 2048, 3840];
const imageTypes = [
['jpeg', 'jpg'],
['webp', 'webp'],
];

test('responsive layout', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="responsive"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-responsive/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);
await expect(img).toHaveScreenshot();

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of ${size}`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-${size}w(-[a-zA-Z0-9-_]+)?.${ext} ${size}w`),
);
}
}
});

test('fixed layout', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="fixed"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-fixed/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);
await expect(img).toHaveAttribute('width', '320');
await expect(img).toHaveAttribute('height', '213');
await expect(img).toHaveScreenshot();

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 1x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 1x`),
);

await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 2x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 2x`),
);
}
}
});

test('fixed layout w/ aspect', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="fixed,aspect"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-fixed/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);
await expect(img).toHaveAttribute('width', '320');
await expect(img).toHaveAttribute('height', '480');
await expect(img).toHaveScreenshot();

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 1x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 1x`),
);

await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 2x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 2x`),
);
}
}
});

test.describe('LQIP', () => {
test('color', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="fixed,lqip-color"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-fixed/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 1x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 1x`),
);

await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 2x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 2x`),
);
}
}
});

test('inline', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="fixed,lqip-inline"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-fixed/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 1x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 1x`),
);

await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 2x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 2x`),
);
}
}
});

test('blurhash', async ({ page }) => {
await page.goto('/');

const img = page.locator('[data-test-local-image="fixed,lqip-blurhash"]');
const picture = page.locator('picture').filter({ has: img });

await expect(img).toHaveClass(/ri-fixed/);
await expect(img).toHaveAttribute(
'src',
new RegExp(`/assets/aurora-[0-9]+w(-[a-zA-Z0-9-_]+)?.jpg`),
);

for (const [type, ext] of imageTypes) {
for (const size of sizes) {
await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 1x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 1x`),
);

await expect(
picture.locator(`source[type="image/${type}"]`),
`has ${type} with a width of 2x`,
).toHaveAttribute(
'srcset',
new RegExp(`/assets/aurora-640w(-[a-zA-Z0-9-_]+)?.${ext} 2x`),
);
}
}
});
});
2 changes: 1 addition & 1 deletion packages/solid/src/responsive-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const ResponsiveImage: Component<ResponsiveImageProps> = (props) => {

const ar = args.src.aspectRatio;
if (ar !== undefined && ar !== 0 && width !== undefined) {
height = width / ar;
height = Math.round(width / ar);
}

// We *must not* set the src attribute before the <img> is actually rendered, and a child of <picture>
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a82ee1e

Please sign in to comment.