wayBetter for X 1.0.2
This commit is contained in:
parent
660531daeb
commit
6f6721d32d
212 changed files with 10208 additions and 2345 deletions
75
apps/desktop/tests/storeKinds.test.ts
Normal file
75
apps/desktop/tests/storeKinds.test.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// The Store's icon-pack and built-in kinds as X configures them: the source folders (store/x/icons/),
|
||||
// the area plugins as `builtin` catalog items with no file to download, the icon pack the app can
|
||||
// import (the same parser Appearance uses), and what the Store view says of each.
|
||||
import assert from 'node:assert/strict';
|
||||
import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import test from 'node:test';
|
||||
// @ts-expect-error: the framework CLI's plain ES module
|
||||
import { buildStore, catalogProblems } from '../../../waybetter/packages/waybetter/cli/store.mjs';
|
||||
import { parseIconPackJson } from '../../../waybetter/packages/runtime/src/themeIcons.ts';
|
||||
// @ts-expect-error: plain ES modules shared with the Store scripts
|
||||
import config from '../../../scripts/store.config.mjs';
|
||||
// @ts-expect-error: plain ES module shared with scripts/check-store.mjs
|
||||
import { readStoreSource } from '../../../scripts/store/source.mjs';
|
||||
import { X_TABLE } from '../src/areas/table.ts';
|
||||
import { filterItems, itemState, type StoreItem } from '../src/shell/installModel.ts';
|
||||
|
||||
const PACK = { id: 'line-2', name: 'Line 2', author: 'me', license: 'CC0-1.0', description: 'Thin lines.', glyphs: { home: { d: 'M3 3h18v18H3z' }, like: { d: 'M4 4h16v16H4z' } } };
|
||||
|
||||
function folder(files: Record<string, unknown>) {
|
||||
const root = mkdtempSync(join(tmpdir(), 'wb-x-store-'));
|
||||
const dir = join(root, 'store/x/icons/line-2');
|
||||
mkdirSync(dir, { recursive: true });
|
||||
for (const [name, value] of Object.entries(files)) writeFileSync(join(dir, name), typeof value === 'string' ? value : JSON.stringify(value));
|
||||
return root;
|
||||
}
|
||||
const read = (root: string) => readStoreSource({ root, app: 'x', bundledDir: root, parseIconPack: parseIconPackJson }) as { entries: Array<Record<string, any>>; problems: string[] };
|
||||
|
||||
test('an icons folder becomes a catalog entry for the pack file, with the pack\'s own words', () => {
|
||||
const { entries, problems } = read(folder({ 'line-2.icons.json': PACK, 'item.json': { category: 'icons', tags: ['line'], credits: 'CRT' } }));
|
||||
assert.deepEqual(problems, []);
|
||||
assert.equal(entries.length, 1);
|
||||
const entry = entries[0]!;
|
||||
assert.deepEqual([entry.kind, entry.id, entry.name, entry.author, entry.license, entry.credits, entry.path], ['icons', 'line-2', 'Line 2', 'me', 'CC0-1.0', 'CRT', 'icons/line-2.icons.json']);
|
||||
assert.equal(entry.preview.path, 'previews/icons-line-2.svg');
|
||||
assert.ok(entry.pack.glyphs.home, 'the parsed pack is kept for the checks');
|
||||
});
|
||||
|
||||
test('an icons folder is refused when the pack is not one, is named differently, or has the wrong files', () => {
|
||||
const problemOf = (files: Record<string, unknown>) => read(folder(files)).problems.join('\n');
|
||||
assert.match(problemOf({ 'line-2.icons.json': { ...PACK, id: 'other' }, 'item.json': { category: 'icons' } }), /folder name/);
|
||||
assert.match(problemOf({ 'line-2.icons.json': { id: 'line-2', name: 'No glyphs' }, 'item.json': { category: 'icons' } }), /glyph/);
|
||||
assert.match(problemOf({ 'line-2.icons.json': '{nope', 'item.json': {} }), /not valid JSON/);
|
||||
assert.match(problemOf({ 'item.json': {} }), /exactly one \*\.icons\.json/);
|
||||
assert.match(problemOf({ 'line-2.icons.json': PACK, 'item.json': { code: 'x' } }), /unknown field "code"/);
|
||||
});
|
||||
|
||||
test('the area plugins are built-in catalog items: no file, nothing to download, one per area, with their words', async () => {
|
||||
const items = (await config.items()) as Array<Record<string, any>>;
|
||||
const built = items.filter(item => item.kind === 'builtin');
|
||||
assert.deepEqual(built.map(item => item.id), X_TABLE.areas.map(area => area.id), 'one item per area, in the table\'s order');
|
||||
for (const item of built) {
|
||||
assert.ok(item.name && item.description && item.category && item.version, item.id);
|
||||
assert.ok(!('path' in item) && !('bytes' in item) && !('file' in item), `${item.id} has no file`);
|
||||
}
|
||||
const out = mkdtempSync(join(tmpdir(), 'wb-x-built-'));
|
||||
const { catalog } = await buildStore({ ...config, items: async () => built }, { out });
|
||||
assert.deepEqual(catalogProblems(catalog, { app: 'x' }), []);
|
||||
for (const item of catalog.items) for (const field of ['url', 'sha256', 'size', 'file']) assert.ok(!(field in item), `${item.id}: no ${field}`);
|
||||
assert.equal(JSON.parse(readFileSync(join(out, 'catalog.v3.json'), 'utf8')).items.length, X_TABLE.areas.length, 'catalog.v3.json lists them');
|
||||
assert.equal(JSON.parse(readFileSync(join(out, 'catalog.json'), 'utf8')).items.length, 0, 'catalog.json (older apps) does not');
|
||||
});
|
||||
|
||||
test('the Store view: a built-in item is an area (its switch), an icon pack follows its record and the packs the owner has', () => {
|
||||
const area = { apps: ['x'], kind: 'builtin', id: 'compose', name: 'Compose+', author: '', version: '1.0.0', description: 'Writing tools.', category: 'writing', tags: [] } as StoreItem;
|
||||
const base = { plugins: {}, records: {}, builtinThemes: [], userThemes: [] as string[] };
|
||||
assert.equal(itemState(area, base).state, 'area');
|
||||
assert.deepEqual(filterItems([area], 'compose', 'builtin', 'writing').map(item => item.id), ['compose']);
|
||||
const pack = { apps: ['x'], kind: 'icons', id: 'line-2', name: 'Line 2', author: 'me', version: '1.0.0', description: 'Thin lines.', category: 'icons', tags: [], url: 'https://waybetter.fyi/store/icons/line-2.icons.json', sha256: 'a'.repeat(64), size: 99 } as StoreItem;
|
||||
assert.equal(itemState(pack, base).state, 'install');
|
||||
const records = { 'icons:line-2': { kind: 'icons' as const, source: 'store' as const, storeId: 'line-2', version: '1.0.0', sha256: 'a'.repeat(64), installedAt: '' } };
|
||||
assert.equal(itemState(pack, { ...base, records, userIcons: ['line-2'] }).state, 'installed');
|
||||
assert.equal(itemState(pack, { ...base, records, userIcons: [] }).state, 'install', 'removed in Appearance: installable again');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue