diff --git a/.envrc b/.envrc index 5de6d36..7d10b8c 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ export DATABASE_URL=sqlite3:./games.db +export VITE_DB_DIR=/dev/ diff --git a/Taskfile.yaml b/Taskfile.yaml index 0277974..c1d7c5b 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -6,6 +6,14 @@ vars: GREETING: Hello, World! tasks: + preview: + deps: [build] + cmds: + - npm exec vite preview + test:e2e: + deps: [build] + cmds: + - npm exec playwright test export-db: cmds: - sqlite3 /home/bggsell/games.db '.mode json' '.once /home/bggsell/db/games.json' 'select * from game' diff --git a/e2e/hide-game.test.js b/e2e/hide-game.test.js new file mode 100644 index 0000000..6facf69 --- /dev/null +++ b/e2e/hide-game.test.js @@ -0,0 +1,20 @@ +import { test, expect } from '@playwright/test'; + +test('hide game', async ({ page }) => { + await page.goto('/'); + const nbr_games = await page + .locator('.games > div') + .all() + .then((games) => games.length); + + await page.getByRole('button', { name: 'visibility' }).first().click(); + + await expect(async () => { + const one_hidden = await page + .locator('.games > div') + .all() + .then((games) => games.length); + + expect(one_hidden).toEqual(nbr_games - 1); + }).toPass({ timeout: 10_000 }); +}); diff --git a/e2e/test.js b/e2e/test.js new file mode 100644 index 0000000..9a28c2b --- /dev/null +++ b/e2e/test.js @@ -0,0 +1,12 @@ +import { expect, test } from '@playwright/test'; + +for (const url of ['/', '/stats/', '/about/']) { + test(url + ' render', async ({ page }) => { + await page.goto(url); + await expect( + page.getByRole('heading', { + name: 'Ottawa board games for sale and trade', + }), + ).toBeVisible(); + }); +} diff --git a/package.json b/package.json index e29b348..0fdaddc 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@changesets/cli": "^2.27.1", - "@playwright/test": "^1.28.1", + "@playwright/test": "^1.41.2", "@sveltejs/kit": "^2.5.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", "@types/eslint": "8.56.0", diff --git a/playwright.config.js b/playwright.config.js index a43c8c0..cb5e35a 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,11 +1,12 @@ /** @type {import('@playwright/test').PlaywrightTestConfig} */ const config = { - webServer: { - command: 'npm run build && npm run preview', - port: 4173 - }, - testDir: 'tests', - testMatch: /(.+\.)?(test|spec)\.[jt]s/ + webServer: { + command: 'npm exec vite preview', + port: 4173, + reuseExistingServer: true, + }, + testDir: 'e2e', + testMatch: /(.+\.)?(test|spec)\.[jt]s/, }; export default config; diff --git a/src/lib/stores/index.js b/src/lib/stores/index.js new file mode 100644 index 0000000..d10d3d8 --- /dev/null +++ b/src/lib/stores/index.js @@ -0,0 +1,51 @@ +import { readable, writable, derived } from 'svelte/store'; +import { dev, browser } from '$app/environment'; +import u from '@yanick/updeep-remeda'; + +const prefix = import.meta.env.VITE_DB_DIR ?? '/db/'; +console.log({ prefix }); + +const _games_store = readable([], (set) => { + if (!browser) return; + + fetch(prefix + 'games.json') + .then((doc) => doc.json()) + .then((games) => + games.map((game) => ({ + ...game, + id: [game.username, game.bgg_id].join('!'), + })), + ) + .then(set); +}); + +export const sellers_store = readable({}, (set) => { + if (!browser) return; + + fetch(prefix + 'sellers.json') + .then((doc) => doc.json()) + .then((sellers_list) => + set( + Object.fromEntries( + sellers_list.map((seller) => [seller.username, seller]), + ), + ), + ); +}); + +let stored = localStorage.getItem('games_hidden'); +if (stored) stored = JSON.parse(stored); +const games_hidden_store = writable(stored || {}); +games_hidden_store.subscribe((data) => + localStorage.setItem('games_hidden', JSON.stringify(data)), +); + +export const games_store = derived( + [_games_store, games_hidden_store], + ([$games, $hidden]) => + $games.map((game) => ({ ...game, is_hidden: $hidden[game.id] })), +); + +games_store.toggle_hidden = (id) => { + games_hidden_store.update(u.updateIn(id, (v) => !v)); +}; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 285837c..3b8afa5 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -15,49 +15,9 @@ import { persisted } from 'svelte-persisted-store'; import u from '@yanick/updeep-remeda'; import AppTop from './AppTop.svelte'; - - const prefix = dev ? '/dev/' : '/db/'; - - const games = readable([], (set) => { - if (!browser) return () => {}; - - fetch(prefix + 'games.json') - .then((doc) => doc.json()) - .then(set); - - return () => {}; - }); - setContext('games', games); - - const sellers = readable({}, (set) => { - if (!browser) return () => {}; - - const sellers_list = fetch(prefix + 'sellers.json') - .then((doc) => doc.json()) - .then((sellers_list) => - set( - Object.fromEntries( - sellers_list.map((seller) => [seller.username, seller]), - ), - ), - ); - return () => {}; - }); - setContext('sellers', sellers); - - const games_hidden = writable( - JSON.parse(localStorage.getItem('games_hidden') || '{}'), - ); - games_hidden.toggle = (username, bgg_id) => { - console.log({ username, bgg_id }); - games_hidden.update( - u.updateIn([username, bgg_id].join('!'), (v) => !v), - ); - }; - setContext('games_hidden', games_hidden); - games_hidden.subscribe((data) => - localStorage.setItem('games_hidden', JSON.stringify(data)), - ); + import { games_store, sellers_store } from '$lib/stores/index.js'; + setContext('games', games_store); + setContext('sellers', sellers_store);