Set up vitest and add tests for interactive

This commit is contained in:
Nate Butler 2023-06-15 18:42:48 -04:00 committed by Mikayla Maki
parent 4bd89c4c8c
commit 5369f2c25a
No known key found for this signature in database
25 changed files with 4546 additions and 2163 deletions

1
styles/.gitignore vendored
View file

@ -1 +1,2 @@
node_modules/
coverage/

2306
styles/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,8 @@
"scripts": {
"build": "ts-node ./src/buildThemes.ts",
"build-licenses": "ts-node ./src/buildLicenses.ts",
"build-tokens": "ts-node ./src/buildTokens.ts"
"build-tokens": "ts-node ./src/buildTokens.ts",
"test": "vitest"
},
"author": "",
"license": "ISC",
@ -22,12 +23,16 @@
"toml": "^3.0.0",
"ts-deepmerge": "^6.0.3",
"ts-node": "^10.9.1",
"utility-types": "^3.10.0"
"utility-types": "^3.10.0",
"vitest": "^0.32.0"
},
"prettier": {
"semi": false,
"printWidth": 80,
"htmlWhitespaceSensitivity": "strict",
"tabWidth": 4
},
"devDependencies": {
"@vitest/coverage-v8": "^0.32.0"
}
}

View file

@ -0,0 +1,3 @@
import { interactive } from "./interactive";
export { interactive }

View file

@ -0,0 +1,59 @@
import { NOT_ENOUGH_STATES_ERROR, NO_DEFAULT_OR_BASE_ERROR, interactive } from './interactive'
import { describe, it, expect } from 'vitest'
describe('interactive', () => {
it('creates an Interactive<Element> with base properties and states', () => {
const result = interactive({
base: { fontSize: 10, color: '#FFFFFF' },
state: {
hovered: { color: '#EEEEEE' },
clicked: { color: '#CCCCCC' },
}
})
expect(result).toEqual({
default: { color: '#FFFFFF', fontSize: 10 },
hovered: { color: '#EEEEEE', fontSize: 10 },
clicked: { color: '#CCCCCC', fontSize: 10 },
})
})
it('creates an Interactive<Element> with no base properties', () => {
const result = interactive({
state: {
default: { color: '#FFFFFF', fontSize: 10 },
hovered: { color: '#EEEEEE' },
clicked: { color: '#CCCCCC' },
}
})
expect(result).toEqual({
default: { color: '#FFFFFF', fontSize: 10 },
hovered: { color: '#EEEEEE', fontSize: 10 },
clicked: { color: '#CCCCCC', fontSize: 10 },
})
})
it('throws error when both default and base are missing', () => {
const state = {
hovered: { color: 'blue' },
}
expect(() => interactive({ state })).toThrow(
NO_DEFAULT_OR_BASE_ERROR
)
})
it('throws error when no other state besides default is present', () => {
const state = {
default: { fontSize: 10 },
}
expect(() => interactive({ state })).toThrow(
NOT_ENOUGH_STATES_ERROR
)
})
})

View file

@ -10,24 +10,27 @@ type Interactive<T> = {
disabled?: T,
};
export const NO_DEFAULT_OR_BASE_ERROR = "An interactive object must have a default state, or a base property."
export const NOT_ENOUGH_STATES_ERROR = "An interactive object must have a default and at least one other state."
interface InteractiveProps<T> {
base?: T,
state: Partial<Record<InteractiveState, T>>
}
/**
* Helper function for creating Interactive<T> objects that works pretty much like Toggle<T>.
* It takes a object to be used as a value for `default` field and then fills out other fields
* with fields from either `base` or `modifications`.
* Notably, it does not touch `hover`, `clicked` and `disabled` if there are no modifications for it.
* Helper function for creating Interactive<T> objects that works with Toggle<T>-like behavior.
* It takes a default object to be used as the value for `default` field and fills out other fields
* with fields from either `base` or from the `state` object which contains values for specific states.
* Notably, it does not touch `hover`, `clicked`, `selected` and `disabled` states if there are no modifications for them.
*
* @param defaultObj Object to be used as the value for `default` field.
* @param base Object containing base fields to be included in the resulting object.
* @param modifications Object containing modified fields to be included in the resulting object.
* @returns Interactive<T> object with fields from `base` and `modifications`.
* @param defaultObj Object to be used as the value for the `default` field.
* @param base Optional object containing base fields to be included in the resulting object.
* @param state Object containing optional modified fields to be included in the resulting object for each state.
* @returns Interactive<T> object with fields from `base` and `state`.
*/
export function interactive<T extends Object>({ base, state }: InteractiveProps<T>): Interactive<T> {
if (!base && !state.default) throw new Error("An interactive object must have a default state, or a base property.");
if (!base && !state.default) throw new Error(NO_DEFAULT_OR_BASE_ERROR);
let defaultState: T;
@ -64,7 +67,7 @@ export function interactive<T extends Object>({ base, state }: InteractiveProps<
}
if (stateCount < 1) {
throw new Error("An interactive object must have a default and at least one other state.");
throw new Error(NOT_ENOUGH_STATES_ERROR);
}
return interactiveObj;

View file

@ -1,7 +1,7 @@
import { ColorScheme } from "../theme/colorScheme"
import { text, border, background, foreground } from "./components"
import editor from "./editor"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function assistant(colorScheme: ColorScheme) {
const layer = colorScheme.highest

View file

@ -2,7 +2,7 @@ import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
import { text, background } from "./components"
import { toggleable } from "./toggle"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function commandPalette(colorScheme: ColorScheme) {
let layer = colorScheme.highest

View file

@ -1,7 +1,7 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, borderColor, foreground, text } from "./components"
import { toggleable } from "./toggle"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function contactsPanel(colorScheme: ColorScheme) {
const nameMargin = 8
const sidePadding = 12

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
const avatarSize = 12
const headerPadding = 8

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, borderColor, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function contextMenu(colorScheme: ColorScheme) {

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, svg, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function copilot(colorScheme: ColorScheme) {
let layer = colorScheme.middle

View file

@ -4,7 +4,7 @@ import { background, border, borderColor, foreground, text } from "./components"
import hoverPopover from "./hoverPopover"
import { buildSyntax } from "../theme/syntax"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function editor(colorScheme: ColorScheme) {

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function feedback(colorScheme: ColorScheme) {
let layer = colorScheme.highest

View file

@ -2,7 +2,7 @@ import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
import { background, border, text } from "./components"
import { toggleable } from "./toggle"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function picker(colorScheme: ColorScheme): any {
let layer = colorScheme.lowest

View file

@ -1,7 +1,7 @@
import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
import { background, border, foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function projectPanel(colorScheme: ColorScheme) {
const { isLight } = colorScheme

View file

@ -1,7 +1,7 @@
import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
import { background, border, foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function search(colorScheme: ColorScheme) {

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
const headerPadding = 8

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function statusBar(colorScheme: ColorScheme) {
let layer = colorScheme.lowest

View file

@ -2,7 +2,7 @@ import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
import { text, border, background, foreground } from "./components"
import { toggleable } from "./toggle"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function tabBar(colorScheme: ColorScheme) {
const height = 32

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { background, border, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import { toggleable } from "./toggle"
export default function dropdownMenu(colorScheme: ColorScheme) {
let layer = colorScheme.middle

View file

@ -1,6 +1,6 @@
import { ColorScheme } from "../theme/colorScheme"
import { foreground, text } from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
const headerPadding = 8

View file

@ -8,7 +8,7 @@ import {
TextProperties,
svg,
} from "./components"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
export default function welcome(colorScheme: ColorScheme) {
let layer = colorScheme.highest

View file

@ -11,7 +11,7 @@ import {
} from "./components"
import statusBar from "./statusBar"
import tabBar from "./tabBar"
import { interactive } from "./interactive"
import { interactive } from "../element/interactive"
import merge from 'ts-deepmerge';
export default function workspace(colorScheme: ColorScheme) {
const layer = colorScheme.lowest

8
styles/vitest.config.ts Normal file
View file

@ -0,0 +1,8 @@
import { configDefaults, defineConfig } from 'vitest/config'
export default defineConfig({
test: {
exclude: [...configDefaults.exclude, 'target/*'],
include: ['src/**/*.{spec,test}.ts'],
},
})