sunpeak 0.8.6 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/commands/build.mjs +3 -3
- package/bin/commands/pull.mjs +2 -2
- package/bin/sunpeak.js +8 -6
- package/dist/chatgpt/chatgpt-simulator.d.ts +1 -2
- package/dist/chatgpt/index.cjs +9 -0
- package/dist/chatgpt/index.cjs.map +1 -0
- package/dist/chatgpt/index.d.ts +3 -1
- package/dist/chatgpt/index.js +9 -0
- package/dist/chatgpt/index.js.map +1 -0
- package/dist/chatgpt/simulator-url.d.ts +127 -0
- package/dist/index.cjs +39 -8448
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -8466
- package/dist/index.js.map +1 -1
- package/dist/mcp/entry.cjs +2 -1
- package/dist/mcp/entry.cjs.map +1 -1
- package/dist/mcp/entry.js +2 -1
- package/dist/mcp/entry.js.map +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/types.d.ts +3 -9
- package/dist/{server-DVmTC-SF.js → server-310A1k9o.js} +2 -2
- package/dist/{server-DVmTC-SF.js.map → server-310A1k9o.js.map} +1 -1
- package/dist/{server-B9YgCQdS.cjs → server-CSybLAYo.cjs} +2 -2
- package/dist/{server-B9YgCQdS.cjs.map → server-CSybLAYo.cjs.map} +1 -1
- package/dist/simulator-url-CG8lAAC3.cjs +8545 -0
- package/dist/simulator-url-CG8lAAC3.cjs.map +1 -0
- package/dist/simulator-url-CexnaL-e.js +8529 -0
- package/dist/simulator-url-CexnaL-e.js.map +1 -0
- package/dist/style.css +5872 -5894
- package/dist/types/simulation.d.ts +6 -32
- package/package.json +7 -3
- package/template/.sunpeak/dev.tsx +8 -7
- package/template/README.md +5 -5
- package/template/dist/albums.js +1 -1
- package/template/dist/albums.json +1 -1
- package/template/dist/carousel.js +1 -1
- package/template/dist/carousel.json +1 -1
- package/template/dist/map.js +1 -1
- package/template/dist/map.json +1 -1
- package/template/dist/review.js +2 -2
- package/template/dist/review.json +1 -1
- package/template/node_modules/.bin/playwright +21 -0
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +3 -3
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_SegmentedControl.js +4 -4
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +20 -20
- package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Textarea.js +3 -3
- package/template/node_modules/.vite/deps/_metadata.json +38 -38
- package/template/node_modules/.vite/deps/{chunk-SPYXUHEY.js → chunk-N6DVYEXK.js} +8 -8
- package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/template/package.json +3 -1
- package/template/playwright.config.ts +26 -0
- package/template/src/resources/index.ts +4 -4
- package/template/src/resources/map-resource.test.tsx +95 -0
- package/template/src/resources/review-resource.test.tsx +538 -0
- package/template/src/resources/review-resource.tsx +6 -1
- package/template/src/simulations/albums-show-simulation.json +1 -1
- package/template/src/simulations/carousel-show-simulation.json +1 -1
- package/template/src/simulations/map-show-simulation.json +1 -1
- package/template/src/simulations/review-diff-simulation.json +1 -1
- package/template/src/simulations/review-post-simulation.json +1 -1
- package/template/src/simulations/review-purchase-simulation.json +1 -1
- package/template/test-results/.last-run.json +4 -0
- package/template/tests/e2e/albums.spec.ts +120 -0
- package/template/tests/e2e/carousel.spec.ts +127 -0
- package/template/tests/e2e/map.spec.ts +188 -0
- package/template/tests/e2e/review.spec.ts +245 -0
- package/template/vitest.config.ts +1 -0
- package/template/dist/counter.js +0 -49
- package/template/dist/counter.json +0 -15
- package/template/src/resources/counter-resource.json +0 -12
- package/template/src/resources/counter-resource.test.tsx +0 -116
- package/template/src/resources/counter-resource.tsx +0 -101
- package/template/src/simulations/counter-show-simulation.json +0 -20
- /package/template/node_modules/.vite/deps/{chunk-SPYXUHEY.js.map → chunk-N6DVYEXK.js.map} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { createSimulatorUrl } from 'sunpeak/chatgpt';
|
|
3
|
+
|
|
4
|
+
test.describe('Albums Resource', () => {
|
|
5
|
+
test.describe('Light Mode', () => {
|
|
6
|
+
test('should render album cards with correct styles', async ({ page }) => {
|
|
7
|
+
await page.goto(createSimulatorUrl({ simulation: 'albums-show', theme: 'light' }));
|
|
8
|
+
|
|
9
|
+
const albumCard = page.locator('button:has-text("Summer Slice")');
|
|
10
|
+
await expect(albumCard).toBeVisible();
|
|
11
|
+
|
|
12
|
+
// Verify album card unique styles
|
|
13
|
+
const styles = await albumCard.evaluate((el) => {
|
|
14
|
+
const computed = window.getComputedStyle(el);
|
|
15
|
+
return {
|
|
16
|
+
cursor: computed.cursor,
|
|
17
|
+
borderRadius: computed.borderRadius,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(styles.cursor).toBe('pointer');
|
|
22
|
+
expect(styles.borderRadius).toBe('12px'); // rounded-xl
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should have album image with correct aspect ratio', async ({ page }) => {
|
|
26
|
+
await page.goto(createSimulatorUrl({ simulation: 'albums-show', theme: 'light' }));
|
|
27
|
+
|
|
28
|
+
const albumImage = page.locator('button:has-text("Summer Slice") img').first();
|
|
29
|
+
await expect(albumImage).toBeVisible();
|
|
30
|
+
|
|
31
|
+
// Verify aspect-[4/3] container
|
|
32
|
+
const imageContainer = page.locator('button:has-text("Summer Slice") .aspect-\\[4\\/3\\]');
|
|
33
|
+
await expect(imageContainer).toBeVisible();
|
|
34
|
+
|
|
35
|
+
const containerStyles = await imageContainer.evaluate((el) => {
|
|
36
|
+
const computed = window.getComputedStyle(el);
|
|
37
|
+
return {
|
|
38
|
+
borderRadius: computed.borderRadius,
|
|
39
|
+
overflow: computed.overflow,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(containerStyles.borderRadius).toBe('12px'); // rounded-xl
|
|
44
|
+
expect(containerStyles.overflow).toBe('hidden');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test.describe('Dark Mode', () => {
|
|
49
|
+
test('should render album cards with correct styles', async ({ page }) => {
|
|
50
|
+
await page.goto(createSimulatorUrl({ simulation: 'albums-show', theme: 'dark' }));
|
|
51
|
+
|
|
52
|
+
const albumCard = page.locator('button:has-text("Summer Slice")');
|
|
53
|
+
await expect(albumCard).toBeVisible();
|
|
54
|
+
|
|
55
|
+
const styles = await albumCard.evaluate((el) => {
|
|
56
|
+
const computed = window.getComputedStyle(el);
|
|
57
|
+
return {
|
|
58
|
+
cursor: computed.cursor,
|
|
59
|
+
borderRadius: computed.borderRadius,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(styles.cursor).toBe('pointer');
|
|
64
|
+
expect(styles.borderRadius).toBe('12px'); // rounded-xl
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('should have text with appropriate contrast', async ({ page }) => {
|
|
68
|
+
await page.goto(createSimulatorUrl({ simulation: 'albums-show', theme: 'dark' }));
|
|
69
|
+
|
|
70
|
+
const albumTitle = page.locator('button:has-text("Summer Slice") .text-primary').first();
|
|
71
|
+
await expect(albumTitle).toBeVisible();
|
|
72
|
+
|
|
73
|
+
// In dark mode, text-primary should be light colored for contrast
|
|
74
|
+
const titleStyles = await albumTitle.evaluate((el) => {
|
|
75
|
+
const computed = window.getComputedStyle(el);
|
|
76
|
+
return {
|
|
77
|
+
color: computed.color,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Verify the text color exists (should be a light color in dark mode)
|
|
82
|
+
expect(titleStyles.color).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test.describe('Fullscreen Mode', () => {
|
|
87
|
+
test('should render correctly in fullscreen displayMode', async ({ page }) => {
|
|
88
|
+
await page.goto(
|
|
89
|
+
createSimulatorUrl({ simulation: 'albums-show', theme: 'light', displayMode: 'fullscreen' })
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Wait for content to load
|
|
93
|
+
await page.waitForLoadState('networkidle');
|
|
94
|
+
|
|
95
|
+
// The root container should be present
|
|
96
|
+
const root = page.locator('#root');
|
|
97
|
+
await expect(root).not.toBeEmpty();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should maintain album card styles in fullscreen', async ({ page }) => {
|
|
101
|
+
await page.goto(
|
|
102
|
+
createSimulatorUrl({ simulation: 'albums-show', theme: 'dark', displayMode: 'fullscreen' })
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const albumCard = page.locator('button:has-text("Summer Slice")');
|
|
106
|
+
await expect(albumCard).toBeVisible();
|
|
107
|
+
|
|
108
|
+
const styles = await albumCard.evaluate((el) => {
|
|
109
|
+
const computed = window.getComputedStyle(el);
|
|
110
|
+
return {
|
|
111
|
+
cursor: computed.cursor,
|
|
112
|
+
borderRadius: computed.borderRadius,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(styles.cursor).toBe('pointer');
|
|
117
|
+
expect(styles.borderRadius).toBe('12px');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { createSimulatorUrl } from 'sunpeak/chatgpt';
|
|
3
|
+
|
|
4
|
+
test.describe('Carousel Resource', () => {
|
|
5
|
+
test.describe('Light Mode', () => {
|
|
6
|
+
test('should render carousel cards with correct styles', async ({ page }) => {
|
|
7
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'light' }));
|
|
8
|
+
|
|
9
|
+
// Wait for carousel to load
|
|
10
|
+
await page.waitForLoadState('networkidle');
|
|
11
|
+
|
|
12
|
+
// Find a card in the carousel
|
|
13
|
+
const card = page.locator('.rounded-2xl').first();
|
|
14
|
+
await expect(card).toBeVisible();
|
|
15
|
+
|
|
16
|
+
const styles = await card.evaluate((el) => {
|
|
17
|
+
const computed = window.getComputedStyle(el);
|
|
18
|
+
return {
|
|
19
|
+
borderRadius: computed.borderRadius,
|
|
20
|
+
cursor: computed.cursor,
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(styles.borderRadius).toBe('16px'); // rounded-2xl
|
|
25
|
+
expect(styles.cursor).toBe('pointer');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should have card with border styling', async ({ page }) => {
|
|
29
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'light' }));
|
|
30
|
+
|
|
31
|
+
await page.waitForLoadState('networkidle');
|
|
32
|
+
|
|
33
|
+
// Cards have border-subtle styling
|
|
34
|
+
const card = page.locator('.rounded-2xl.border').first();
|
|
35
|
+
await expect(card).toBeVisible();
|
|
36
|
+
|
|
37
|
+
const styles = await card.evaluate((el) => {
|
|
38
|
+
const computed = window.getComputedStyle(el);
|
|
39
|
+
return {
|
|
40
|
+
borderWidth: computed.borderWidth,
|
|
41
|
+
borderStyle: computed.borderStyle,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(styles.borderWidth).toBe('1px');
|
|
46
|
+
expect(styles.borderStyle).toBe('solid');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should have interactive buttons', async ({ page }) => {
|
|
50
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'light' }));
|
|
51
|
+
|
|
52
|
+
await page.waitForLoadState('networkidle');
|
|
53
|
+
|
|
54
|
+
// Find the Visit button (primary button)
|
|
55
|
+
const visitButton = page.locator('button:has-text("Visit")').first();
|
|
56
|
+
await expect(visitButton).toBeAttached();
|
|
57
|
+
|
|
58
|
+
const styles = await visitButton.evaluate((el) => {
|
|
59
|
+
const computed = window.getComputedStyle(el);
|
|
60
|
+
return {
|
|
61
|
+
cursor: computed.cursor,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(styles.cursor).toBe('pointer');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test.describe('Dark Mode', () => {
|
|
70
|
+
test('should render carousel cards with correct styles', async ({ page }) => {
|
|
71
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'dark' }));
|
|
72
|
+
|
|
73
|
+
await page.waitForLoadState('networkidle');
|
|
74
|
+
|
|
75
|
+
const card = page.locator('.rounded-2xl').first();
|
|
76
|
+
await expect(card).toBeVisible();
|
|
77
|
+
|
|
78
|
+
const styles = await card.evaluate((el) => {
|
|
79
|
+
const computed = window.getComputedStyle(el);
|
|
80
|
+
return {
|
|
81
|
+
borderRadius: computed.borderRadius,
|
|
82
|
+
cursor: computed.cursor,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(styles.borderRadius).toBe('16px'); // rounded-2xl
|
|
87
|
+
expect(styles.cursor).toBe('pointer');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should have appropriate background color for dark mode', async ({ page }) => {
|
|
91
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'dark' }));
|
|
92
|
+
|
|
93
|
+
await page.waitForLoadState('networkidle');
|
|
94
|
+
|
|
95
|
+
// Verify the card has a background color set
|
|
96
|
+
const card = page.locator('.rounded-2xl.bg-surface').first();
|
|
97
|
+
await expect(card).toBeVisible();
|
|
98
|
+
|
|
99
|
+
const styles = await card.evaluate((el) => {
|
|
100
|
+
const computed = window.getComputedStyle(el);
|
|
101
|
+
return {
|
|
102
|
+
backgroundColor: computed.backgroundColor,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Background color should be set (not transparent)
|
|
107
|
+
expect(styles.backgroundColor).toBeTruthy();
|
|
108
|
+
expect(styles.backgroundColor).not.toBe('rgba(0, 0, 0, 0)');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should load without console errors', async ({ page }) => {
|
|
112
|
+
const errors: string[] = [];
|
|
113
|
+
page.on('console', (msg) => {
|
|
114
|
+
if (msg.type() === 'error') {
|
|
115
|
+
errors.push(msg.text());
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await page.goto(createSimulatorUrl({ simulation: 'carousel-show', theme: 'dark' }));
|
|
120
|
+
await page.waitForLoadState('networkidle');
|
|
121
|
+
|
|
122
|
+
expect(errors).toHaveLength(0);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Note: No fullscreen test for carousel as per requirements
|
|
127
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { createSimulatorUrl } from 'sunpeak/chatgpt';
|
|
3
|
+
|
|
4
|
+
test.describe('Map Resource', () => {
|
|
5
|
+
test.describe('Light Mode', () => {
|
|
6
|
+
test('should render map container with correct styles', async ({ page }) => {
|
|
7
|
+
await page.goto(createSimulatorUrl({ simulation: 'map-show', theme: 'light' }));
|
|
8
|
+
|
|
9
|
+
// Wait for the map component to render
|
|
10
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
11
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
12
|
+
|
|
13
|
+
const styles = await mapContainer.evaluate((el) => {
|
|
14
|
+
const computed = window.getComputedStyle(el);
|
|
15
|
+
return {
|
|
16
|
+
overflow: computed.overflow,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(styles.overflow).toBe('hidden');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('should have rounded border in inline mode', async ({ page }) => {
|
|
24
|
+
await page.goto(
|
|
25
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'light', displayMode: 'inline' })
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Wait for the inner container with rounded borders
|
|
29
|
+
const innerContainer = page.locator('.border.rounded-2xl').first();
|
|
30
|
+
await expect(innerContainer).toBeVisible({ timeout: 10000 });
|
|
31
|
+
|
|
32
|
+
const styles = await innerContainer.evaluate((el) => {
|
|
33
|
+
const computed = window.getComputedStyle(el);
|
|
34
|
+
return {
|
|
35
|
+
borderRadius: computed.borderRadius,
|
|
36
|
+
borderWidth: computed.borderWidth,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Should have rounded corners (rounded-2xl = 16px)
|
|
41
|
+
expect(parseInt(styles.borderRadius)).toBeGreaterThanOrEqual(16);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should have fullscreen expand button in inline mode', async ({ page }) => {
|
|
45
|
+
await page.goto(
|
|
46
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'light', displayMode: 'inline' })
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Wait for the expand button
|
|
50
|
+
const expandButton = page.locator('button[aria-label="Enter fullscreen"]');
|
|
51
|
+
await expect(expandButton).toBeVisible({ timeout: 10000 });
|
|
52
|
+
|
|
53
|
+
const styles = await expandButton.evaluate((el) => {
|
|
54
|
+
const computed = window.getComputedStyle(el);
|
|
55
|
+
return {
|
|
56
|
+
cursor: computed.cursor,
|
|
57
|
+
position: computed.position,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(styles.cursor).toBe('pointer');
|
|
62
|
+
expect(styles.position).toBe('absolute');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should load without console errors', async ({ page }) => {
|
|
66
|
+
const errors: string[] = [];
|
|
67
|
+
page.on('console', (msg) => {
|
|
68
|
+
if (msg.type() === 'error') {
|
|
69
|
+
errors.push(msg.text());
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await page.goto(createSimulatorUrl({ simulation: 'map-show', theme: 'light' }));
|
|
74
|
+
|
|
75
|
+
// Wait for map to render
|
|
76
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
77
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
78
|
+
|
|
79
|
+
expect(errors).toHaveLength(0);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test.describe('Dark Mode', () => {
|
|
84
|
+
test('should render map container with correct styles', async ({ page }) => {
|
|
85
|
+
await page.goto(createSimulatorUrl({ simulation: 'map-show', theme: 'dark' }));
|
|
86
|
+
|
|
87
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
88
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('should have appropriate border color for dark mode', async ({ page }) => {
|
|
92
|
+
await page.goto(
|
|
93
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'dark', displayMode: 'inline' })
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// In dark mode, the border uses dark:border-white/10
|
|
97
|
+
const innerContainer = page.locator('.border.rounded-2xl').first();
|
|
98
|
+
await expect(innerContainer).toBeVisible({ timeout: 10000 });
|
|
99
|
+
|
|
100
|
+
const styles = await innerContainer.evaluate((el) => {
|
|
101
|
+
const computed = window.getComputedStyle(el);
|
|
102
|
+
return {
|
|
103
|
+
borderColor: computed.borderColor,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Border color should be set
|
|
108
|
+
expect(styles.borderColor).toBeTruthy();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should load without console errors', async ({ page }) => {
|
|
112
|
+
const errors: string[] = [];
|
|
113
|
+
page.on('console', (msg) => {
|
|
114
|
+
if (msg.type() === 'error') {
|
|
115
|
+
errors.push(msg.text());
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await page.goto(createSimulatorUrl({ simulation: 'map-show', theme: 'dark' }));
|
|
120
|
+
|
|
121
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
122
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
123
|
+
|
|
124
|
+
expect(errors).toHaveLength(0);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test.describe('Fullscreen Mode', () => {
|
|
129
|
+
test('should not have rounded border in fullscreen mode', async ({ page }) => {
|
|
130
|
+
await page.goto(
|
|
131
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'light', displayMode: 'fullscreen' })
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// In fullscreen, the container uses rounded-none and border-0
|
|
135
|
+
const innerContainer = page.locator('.rounded-none.border-0').first();
|
|
136
|
+
await expect(innerContainer).toBeVisible({ timeout: 10000 });
|
|
137
|
+
|
|
138
|
+
const styles = await innerContainer.evaluate((el) => {
|
|
139
|
+
const computed = window.getComputedStyle(el);
|
|
140
|
+
return {
|
|
141
|
+
borderRadius: computed.borderRadius,
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(styles.borderRadius).toBe('0px');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('should not show fullscreen button when already in fullscreen', async ({ page }) => {
|
|
149
|
+
await page.goto(
|
|
150
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'light', displayMode: 'fullscreen' })
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// Wait for content to render
|
|
154
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
155
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
156
|
+
|
|
157
|
+
// The expand button should not be visible in fullscreen mode
|
|
158
|
+
const expandButton = page.locator('button[aria-label="Enter fullscreen"]');
|
|
159
|
+
await expect(expandButton).not.toBeVisible();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('should show place list sidebar in fullscreen', async ({ page }) => {
|
|
163
|
+
await page.goto(
|
|
164
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'dark', displayMode: 'fullscreen' })
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// The map container should be present
|
|
168
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
169
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('should show suggestion chips in fullscreen on desktop', async ({ page }) => {
|
|
173
|
+
// Set viewport to desktop size
|
|
174
|
+
await page.setViewportSize({ width: 1024, height: 768 });
|
|
175
|
+
await page.goto(
|
|
176
|
+
createSimulatorUrl({ simulation: 'map-show', theme: 'light', displayMode: 'fullscreen' })
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Wait for map to render
|
|
180
|
+
const mapContainer = page.locator('.antialiased.w-full.overflow-hidden').first();
|
|
181
|
+
await expect(mapContainer).toBeVisible({ timeout: 10000 });
|
|
182
|
+
|
|
183
|
+
// Suggestion chips should be visible (contains "Open now", "Top rated", etc.)
|
|
184
|
+
const openNowChip = page.locator('button:has-text("Open now")');
|
|
185
|
+
await expect(openNowChip).toBeVisible({ timeout: 5000 });
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { createSimulatorUrl } from 'sunpeak/chatgpt';
|
|
3
|
+
|
|
4
|
+
test.describe('Review Resource', () => {
|
|
5
|
+
test.describe('Light Mode', () => {
|
|
6
|
+
test('should render review title with correct styles', async ({ page }) => {
|
|
7
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'light' }));
|
|
8
|
+
|
|
9
|
+
await page.waitForLoadState('networkidle');
|
|
10
|
+
|
|
11
|
+
// Review has a title
|
|
12
|
+
const title = page.locator('h1:has-text("Refactor Authentication Module")');
|
|
13
|
+
await expect(title).toBeVisible();
|
|
14
|
+
|
|
15
|
+
const styles = await title.evaluate((el) => {
|
|
16
|
+
const computed = window.getComputedStyle(el);
|
|
17
|
+
return {
|
|
18
|
+
fontWeight: computed.fontWeight,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Should be semibold (600)
|
|
23
|
+
expect(parseInt(styles.fontWeight)).toBeGreaterThanOrEqual(600);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('should render change items with type-specific styling', async ({ page }) => {
|
|
27
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'light' }));
|
|
28
|
+
|
|
29
|
+
await page.waitForLoadState('networkidle');
|
|
30
|
+
|
|
31
|
+
// Review diff shows changes - find the list items
|
|
32
|
+
const changeItem = page.locator('li').first();
|
|
33
|
+
await expect(changeItem).toBeVisible();
|
|
34
|
+
|
|
35
|
+
const styles = await changeItem.evaluate((el) => {
|
|
36
|
+
const computed = window.getComputedStyle(el);
|
|
37
|
+
return {
|
|
38
|
+
borderRadius: computed.borderRadius,
|
|
39
|
+
backgroundColor: computed.backgroundColor,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Background should be set (one of the type colors)
|
|
44
|
+
expect(styles.backgroundColor).toBeTruthy();
|
|
45
|
+
expect(styles.backgroundColor).not.toBe('rgba(0, 0, 0, 0)');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('should have interactive apply and cancel buttons', async ({ page }) => {
|
|
49
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'light' }));
|
|
50
|
+
|
|
51
|
+
await page.waitForLoadState('networkidle');
|
|
52
|
+
|
|
53
|
+
// Find the Apply Changes button (based on simulation data)
|
|
54
|
+
const applyButton = page.locator('button:has-text("Apply Changes")');
|
|
55
|
+
await expect(applyButton).toBeVisible();
|
|
56
|
+
|
|
57
|
+
const applyStyles = await applyButton.evaluate((el) => {
|
|
58
|
+
const computed = window.getComputedStyle(el);
|
|
59
|
+
return {
|
|
60
|
+
cursor: computed.cursor,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
expect(applyStyles.cursor).toBe('pointer');
|
|
64
|
+
|
|
65
|
+
// Find the Cancel button
|
|
66
|
+
const cancelButton = page.locator('button:has-text("Cancel")');
|
|
67
|
+
await expect(cancelButton).toBeVisible();
|
|
68
|
+
|
|
69
|
+
const cancelStyles = await cancelButton.evaluate((el) => {
|
|
70
|
+
const computed = window.getComputedStyle(el);
|
|
71
|
+
return {
|
|
72
|
+
cursor: computed.cursor,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
expect(cancelStyles.cursor).toBe('pointer');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should have expand fullscreen button in inline mode', async ({ page }) => {
|
|
79
|
+
await page.goto(
|
|
80
|
+
createSimulatorUrl({ simulation: 'review-diff', theme: 'light', displayMode: 'inline' })
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
await page.waitForLoadState('networkidle');
|
|
84
|
+
|
|
85
|
+
// Find the expand button
|
|
86
|
+
const expandButton = page.locator('button[aria-label="Enter fullscreen"]');
|
|
87
|
+
await expect(expandButton).toBeVisible();
|
|
88
|
+
|
|
89
|
+
const styles = await expandButton.evaluate((el) => {
|
|
90
|
+
const computed = window.getComputedStyle(el);
|
|
91
|
+
return {
|
|
92
|
+
cursor: computed.cursor,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(styles.cursor).toBe('pointer');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test.describe('Dark Mode', () => {
|
|
101
|
+
test('should render review title with correct styles', async ({ page }) => {
|
|
102
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'dark' }));
|
|
103
|
+
|
|
104
|
+
await page.waitForLoadState('networkidle');
|
|
105
|
+
|
|
106
|
+
const title = page.locator('h1:has-text("Refactor Authentication Module")');
|
|
107
|
+
await expect(title).toBeVisible();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('should have appropriate text colors for dark mode', async ({ page }) => {
|
|
111
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'dark' }));
|
|
112
|
+
|
|
113
|
+
await page.waitForLoadState('networkidle');
|
|
114
|
+
|
|
115
|
+
// The title should have text-primary class
|
|
116
|
+
const title = page.locator('h1.text-primary').first();
|
|
117
|
+
await expect(title).toBeVisible();
|
|
118
|
+
|
|
119
|
+
const styles = await title.evaluate((el) => {
|
|
120
|
+
const computed = window.getComputedStyle(el);
|
|
121
|
+
return {
|
|
122
|
+
color: computed.color,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// In dark mode, text color should be light
|
|
127
|
+
expect(styles.color).toBeTruthy();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should render change items in dark mode', async ({ page }) => {
|
|
131
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'dark' }));
|
|
132
|
+
|
|
133
|
+
await page.waitForLoadState('networkidle');
|
|
134
|
+
|
|
135
|
+
const changeItem = page.locator('li').first();
|
|
136
|
+
await expect(changeItem).toBeVisible();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('should load without console errors', async ({ page }) => {
|
|
140
|
+
const errors: string[] = [];
|
|
141
|
+
page.on('console', (msg) => {
|
|
142
|
+
if (msg.type() === 'error') {
|
|
143
|
+
errors.push(msg.text());
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-diff', theme: 'dark' }));
|
|
148
|
+
await page.waitForLoadState('networkidle');
|
|
149
|
+
|
|
150
|
+
expect(errors).toHaveLength(0);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test.describe('Fullscreen Mode', () => {
|
|
155
|
+
test('should not show fullscreen button when already in fullscreen', async ({ page }) => {
|
|
156
|
+
await page.goto(
|
|
157
|
+
createSimulatorUrl({ simulation: 'review-diff', theme: 'light', displayMode: 'fullscreen' })
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
await page.waitForLoadState('networkidle');
|
|
161
|
+
|
|
162
|
+
// The expand button should not be visible in fullscreen mode
|
|
163
|
+
const expandButton = page.locator('button[aria-label="Enter fullscreen"]');
|
|
164
|
+
await expect(expandButton).not.toBeVisible();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('should render content correctly in fullscreen', async ({ page }) => {
|
|
168
|
+
await page.goto(
|
|
169
|
+
createSimulatorUrl({ simulation: 'review-diff', theme: 'dark', displayMode: 'fullscreen' })
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
await page.waitForLoadState('networkidle');
|
|
173
|
+
|
|
174
|
+
// The root content should be present
|
|
175
|
+
const root = page.locator('#root');
|
|
176
|
+
await expect(root).not.toBeEmpty();
|
|
177
|
+
|
|
178
|
+
// Title should be visible
|
|
179
|
+
const title = page.locator('h1');
|
|
180
|
+
await expect(title).toBeVisible();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('should have scrollable content area in fullscreen', async ({ page }) => {
|
|
184
|
+
await page.goto(
|
|
185
|
+
createSimulatorUrl({ simulation: 'review-diff', theme: 'light', displayMode: 'fullscreen' })
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
await page.waitForLoadState('networkidle');
|
|
189
|
+
|
|
190
|
+
// The content area should have overflow-y-auto
|
|
191
|
+
const contentArea = page.locator('.overflow-y-auto').first();
|
|
192
|
+
await expect(contentArea).toBeVisible();
|
|
193
|
+
|
|
194
|
+
const styles = await contentArea.evaluate((el) => {
|
|
195
|
+
const computed = window.getComputedStyle(el);
|
|
196
|
+
return {
|
|
197
|
+
overflowY: computed.overflowY,
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(styles.overflowY).toBe('auto');
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test.describe('Review Post Simulation', () => {
|
|
206
|
+
test('should render post review in light mode', async ({ page }) => {
|
|
207
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-post', theme: 'light' }));
|
|
208
|
+
|
|
209
|
+
await page.waitForLoadState('networkidle');
|
|
210
|
+
|
|
211
|
+
// Should render the review content
|
|
212
|
+
const root = page.locator('#root');
|
|
213
|
+
await expect(root).not.toBeEmpty();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('should render post review in dark mode', async ({ page }) => {
|
|
217
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-post', theme: 'dark' }));
|
|
218
|
+
|
|
219
|
+
await page.waitForLoadState('networkidle');
|
|
220
|
+
|
|
221
|
+
const root = page.locator('#root');
|
|
222
|
+
await expect(root).not.toBeEmpty();
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test.describe('Review Purchase Simulation', () => {
|
|
227
|
+
test('should render purchase review in light mode', async ({ page }) => {
|
|
228
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-purchase', theme: 'light' }));
|
|
229
|
+
|
|
230
|
+
await page.waitForLoadState('networkidle');
|
|
231
|
+
|
|
232
|
+
const root = page.locator('#root');
|
|
233
|
+
await expect(root).not.toBeEmpty();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('should render purchase review in dark mode', async ({ page }) => {
|
|
237
|
+
await page.goto(createSimulatorUrl({ simulation: 'review-purchase', theme: 'dark' }));
|
|
238
|
+
|
|
239
|
+
await page.waitForLoadState('networkidle');
|
|
240
|
+
|
|
241
|
+
const root = page.locator('#root');
|
|
242
|
+
await expect(root).not.toBeEmpty();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|