Skip to content

Commit b79f1ac

Browse files
authored
Merge pull request #808 from spences10/refactor/new-testing-approach
2 parents 3dd1283 + c6a73fb commit b79f1ac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+7122
-1240
lines changed

.github/workflows/unit-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ jobs:
2828
version: '^8.0.0'
2929
- name: Install dependencies
3030
run: pnpm recursive install
31+
- name: Install Playwright browsers
32+
run: pnpm exec playwright install chromium --with-deps
33+
working-directory: packages/sveltekit-embed
3134
- name: Run unit tests
3235
run: pnpm run test:ci
3336
working-directory: packages/sveltekit-embed

packages/sveltekit-embed/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ vite.config.js.timestamp-*
1111
vite.config.ts.timestamp-*
1212
.vercel
1313
.env*.local
14+
/coverage

packages/sveltekit-embed/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# SvelteKit Embed 🌱
22

3-
[docs](../../README.md)
3+
[docs](../../README.md)
File renamed without changes.

packages/sveltekit-embed/package.json

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
2828
"lint": "prettier --check . && eslint .",
2929
"format": "prettier --write .",
30+
"coverage": "pnpm exec vitest run --coverage",
3031
"test:integration": "playwright test",
3132
"test:unit": "vitest",
3233
"test:ci": "vitest run"
@@ -46,31 +47,39 @@
4647
"svelte": "^4.0.0 || ^5.0.0"
4748
},
4849
"devDependencies": {
50+
"@eslint/compat": "^1.2.9",
51+
"@eslint/js": "^9.27.0",
4952
"@playwright/test": "^1.52.0",
50-
"@sveltejs/adapter-auto": "^4.0.0",
51-
"@sveltejs/kit": "^2.20.7",
53+
"@sveltejs/adapter-auto": "^6.0.1",
54+
"@sveltejs/kit": "^2.21.1",
5255
"@sveltejs/package": "^2.3.11",
5356
"@sveltejs/vite-plugin-svelte": "^5.0.3",
54-
"@testing-library/svelte": "^5.2.7",
55-
"@types/eslint": "^9.6.1",
56-
"@typescript-eslint/eslint-plugin": "^8.31.0",
57-
"@typescript-eslint/parser": "^8.31.0",
58-
"eslint": "^9.25.1",
59-
"eslint-config-prettier": "^10.1.2",
60-
"eslint-plugin-svelte": "^2.46.1",
57+
"@vitest/browser": "^3.1.4",
58+
"@vitest/coverage-v8": "3.1.4",
59+
"eslint": "^9.27.0",
60+
"eslint-config-prettier": "^10.1.5",
61+
"eslint-plugin-svelte": "^3.9.0",
6162
"fathom-client": "^3.7.2",
63+
"globals": "^16.1.0",
6264
"jsdom": "^26.1.0",
6365
"prettier": "^3.5.3",
64-
"prettier-plugin-svelte": "^3.3.3",
65-
"publint": "^0.3.2",
66-
"svelte": "5.28.2",
67-
"svelte-check": "^4.1.6",
68-
"tslib": "^2.8.1",
66+
"prettier-plugin-svelte": "^3.4.0",
67+
"prettier-plugin-tailwindcss": "^0.6.11",
68+
"publint": "^0.3.12",
69+
"svelte": "5.33.1",
70+
"svelte-check": "^4.2.1",
6971
"typescript": "^5.8.3",
70-
"vite": "^6.3.3",
71-
"vitest": "^3.1.2"
72+
"typescript-eslint": "^8.32.1",
73+
"vite": "^6.3.5",
74+
"vitest": "^3.1.4",
75+
"vitest-browser-svelte": "^0.1.0"
7276
},
7377
"svelte": "./dist/index.js",
7478
"types": "./dist/index.d.ts",
75-
"type": "module"
79+
"type": "module",
80+
"pnpm": {
81+
"onlyBuiltDependencies": [
82+
"esbuild"
83+
]
84+
}
7685
}
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import type { PlaywrightTestConfig } from '@playwright/test';
1+
import { defineConfig } from '@playwright/test';
22

3-
const config: PlaywrightTestConfig = {
3+
export default defineConfig({
44
webServer: {
5-
command: 'npm run build && npm run preview',
5+
command: 'npm run build && PORT=4173 node build/index.js',
66
port: 4173,
77
},
8-
testDir: 'tests',
9-
testMatch: /(.+\.)?(test|spec)\.[jt]s/,
10-
};
11-
12-
export default config;
8+
testDir: 'e2e',
9+
});

packages/sveltekit-embed/src/index.test.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import AnchorFm from '$lib/components/anchor-fm.svelte';
2+
import { describe, expect, it } from 'vitest';
3+
import { render } from 'vitest-browser-svelte';
4+
5+
let episodeUrl =
6+
'purrfect-dev/embed/episodes/1-31---Delivering-Digital-Content-with-GraphCMS-e14g55c/a-a650v9a';
7+
8+
describe('AnchorFm', () => {
9+
it('mounts with episode url', async () => {
10+
const { container } = render(AnchorFm, {
11+
episodeUrl,
12+
disable_observer: true,
13+
});
14+
expect(container).toBeTruthy();
15+
});
16+
17+
it('renders iframe with episode url', async () => {
18+
const { getByTestId } = render(AnchorFm, {
19+
episodeUrl,
20+
disable_observer: true,
21+
});
22+
const iframe = getByTestId('anchor-fm-episode');
23+
const expected_src = `https://anchor.fm/${episodeUrl}`;
24+
await expect.element(iframe).toHaveAttribute('src', expected_src);
25+
});
26+
27+
it('mounts with custom height and width', async () => {
28+
const { container } = render(AnchorFm, {
29+
episodeUrl,
30+
height: '200px',
31+
width: '50%',
32+
disable_observer: true,
33+
});
34+
const iframe = container.querySelector('iframe');
35+
36+
expect(iframe?.parentElement?.style.height).toBe('200px');
37+
expect(iframe?.parentElement?.style.width).toBe('50%');
38+
});
39+
40+
it('renders with a GeneralObserver', async () => {
41+
const { getByTestId } = render(AnchorFm, {
42+
episodeUrl,
43+
disable_observer: false,
44+
});
45+
const general_observer = getByTestId('general-observer');
46+
await expect.element(general_observer).toBeInTheDocument();
47+
});
48+
49+
// Coverage gaps - test stubs to implement
50+
it('should handle empty episodeUrl gracefully', async () => {
51+
// Test edge case: empty or invalid episode URL
52+
const { getByTestId } = render(AnchorFm, {
53+
episodeUrl: '',
54+
disable_observer: true,
55+
});
56+
const iframe = getByTestId('anchor-fm-episode');
57+
await expect
58+
.element(iframe)
59+
.toHaveAttribute('src', 'https://anchor.fm/');
60+
await expect
61+
.element(iframe)
62+
.toHaveAttribute('title', 'anchor-fm-');
63+
});
64+
65+
it('should apply default height and width when not provided', async () => {
66+
// Test default prop values (height: '100px', width: '100%')
67+
const { container } = render(AnchorFm, {
68+
episodeUrl,
69+
disable_observer: true,
70+
});
71+
const iframe = container.querySelector('iframe');
72+
73+
expect(iframe?.parentElement?.style.height).toBe('100px');
74+
expect(iframe?.parentElement?.style.width).toBe('100%');
75+
});
76+
77+
it('should handle special characters in episodeUrl', async () => {
78+
// Test URL encoding and special characters
79+
const specialUrl =
80+
'test-podcast/episodes/episode-with-special-chars-!@#$%^&*()';
81+
const { getByTestId } = render(AnchorFm, {
82+
episodeUrl: specialUrl,
83+
disable_observer: true,
84+
});
85+
const iframe = getByTestId('anchor-fm-episode');
86+
const expectedSrc = `https://anchor.fm/${specialUrl}`;
87+
await expect.element(iframe).toHaveAttribute('src', expectedSrc);
88+
await expect
89+
.element(iframe)
90+
.toHaveAttribute('title', `anchor-fm-${specialUrl}`);
91+
});
92+
93+
it('should have proper iframe accessibility attributes', async () => {
94+
// Test title attribute, aria-labels, etc.
95+
const { getByTestId } = render(AnchorFm, {
96+
episodeUrl,
97+
disable_observer: true,
98+
});
99+
const iframe = getByTestId('anchor-fm-episode');
100+
101+
await expect
102+
.element(iframe)
103+
.toHaveAttribute('title', `anchor-fm-${episodeUrl}`);
104+
await expect.element(iframe).toHaveAttribute('frameborder', '0');
105+
await expect.element(iframe).toHaveAttribute('scrolling', 'no');
106+
});
107+
108+
it('should handle very long episodeUrl values', async () => {
109+
// Test edge case: extremely long URLs
110+
const longUrl = 'a'.repeat(1000) + '/episodes/' + 'b'.repeat(500);
111+
const { getByTestId } = render(AnchorFm, {
112+
episodeUrl: longUrl,
113+
disable_observer: true,
114+
});
115+
const iframe = getByTestId('anchor-fm-episode');
116+
const expectedSrc = `https://anchor.fm/${longUrl}`;
117+
await expect.element(iframe).toHaveAttribute('src', expectedSrc);
118+
});
119+
120+
it('should apply custom CSS styles correctly', async () => {
121+
// Test that custom height/width styles are properly applied
122+
const customHeight = '300px';
123+
const customWidth = '75%';
124+
const { container } = render(AnchorFm, {
125+
episodeUrl,
126+
height: customHeight,
127+
width: customWidth,
128+
disable_observer: true,
129+
});
130+
const iframe = container.querySelector('iframe');
131+
const wrapperDiv = iframe?.parentElement;
132+
133+
expect(wrapperDiv?.style.height).toBe(customHeight);
134+
expect(wrapperDiv?.style.width).toBe(customWidth);
135+
expect(wrapperDiv?.style.position).toBe('relative');
136+
137+
// Check iframe styles
138+
expect(iframe?.style.position).toBe('absolute');
139+
expect(iframe?.style.top).toBe('0px');
140+
expect(iframe?.style.left).toBe('0px');
141+
expect(iframe?.style.width).toBe('100%');
142+
expect(iframe?.style.height).toBe('100%');
143+
});
144+
145+
it('should handle numeric height and width values', async () => {
146+
// Test passing numbers instead of strings for dimensions
147+
const { container } = render(AnchorFm, {
148+
episodeUrl,
149+
height: '250px',
150+
width: '80%',
151+
disable_observer: true,
152+
});
153+
const iframe = container.querySelector('iframe');
154+
155+
// Component should handle numeric values by converting them
156+
expect(iframe?.parentElement?.style.height).toBe('250px');
157+
expect(iframe?.parentElement?.style.width).toBe('80%');
158+
});
159+
});

packages/sveltekit-embed/src/lib/components/anchor-fm.test.ts

Lines changed: 0 additions & 50 deletions
This file was deleted.

0 commit comments

Comments
 (0)