PronounsPage/composables/useDialogue.ts
Adaline Simonian 23a3862ca0
test: introduce snapshot-based smoke tests
- Adds a new test suite with Docker-based smoke tests for all locales.
  Can be run using the ./smoketest.sh script.
- Replaces all calls to Math.random() with a new helper that returns 0.5
  in snapshot testing mode, ensuring deterministic snapshots.
- Similarly replaces all calls to new Date() and Date.now() with new
  helpers that return a fixed date in snapshot testing mode.
- Replaces checks against NODE_ENV with APP_ENV, to ensure that the
  bundles can be built with Nuxt for testing without losing code that
  would otherwise be stripped out by production optimizations.
- Adds a database init script that can be used to initialize the
  database with a single admin user and a long-lived JWT token for use
  in automation tests.
- Adds a JWT decoding/encoding CLI tool for debugging JWTs.

Note: Snapshots are not checked in, and must be generated manually. See
test/__snapshots__/.gitignore for more information.
2025-02-02 23:11:19 -08:00

121 lines
4.0 KiB
TypeScript

import { useNuxtApp } from 'nuxt/app';
import type { FetchOptions } from 'ofetch';
import { getCurrentInstance, h, render } from 'vue';
import DialogueBox from '../components/DialogueBox.vue';
import type { DialogueMessage } from '../components/DialogueBox.vue';
import type { Color, ModalSize } from '../src/bootstrap.ts';
import { random } from '../src/helpers.ts';
export default (to: string = 'body') => {
const { $translator: translator } = useNuxtApp();
const self = getCurrentInstance()!;
const show = (
choice: boolean,
message: string | DialogueMessage,
colour: Color,
value: string | string[] | undefined,
size: ModalSize,
): Promise<string | string[] | undefined> => {
return new Promise((resolve, reject) => {
if (typeof message === 'string') {
message = { message };
}
const vnode = h(DialogueBox, {
choice,
icon: message.icon || (choice ? 'map-marker-question' : undefined),
header: message.header,
message: message.message || (choice ? translator.translate('confirm.header') : undefined),
margin: message.margin ?? true,
colour,
value,
size: message.size ?? size,
onConfirm: (value) => {
hide();
resolve(value);
},
onCancel: () => {
hide();
reject();
},
});
vnode.key = random();
vnode.appContext = self.appContext;
render(vnode, document.querySelector(to)!);
});
};
const hide = () => {
render(null, document.querySelector(to)!);
};
const alert = (
message: string | DialogueMessage,
color: Color = 'primary',
): Promise<void> => {
return show(false, message, color, undefined, undefined).then(() => undefined);
};
const confirm = (
message: string | DialogueMessage = '',
colour: Color = 'primary',
): Promise<void> => {
return show(true, message, colour, undefined, undefined).then(() => undefined);
};
const editor = (
value: string | string[],
message: string | DialogueMessage = '',
color: Color = 'primary',
): Promise<string | string[] | undefined> => {
return show(false, message, color, value, 'lg');
};
const alertRaw = (
message: string | DialogueMessage,
color: Color = 'primary',
): Promise<void> => {
return show(false, `<pre class="text-start"><code>${message}</code></pre>`, color, undefined, 'lg').then(() => undefined);
};
const postWithAlertOnError = async <T = unknown>(
url: string,
data: BodyInit | Record<string, unknown> | null | undefined = undefined,
options: Omit<FetchOptions, 'method' | 'data' | 'timeout'> = {},
timeout = 30000,
): Promise<T> => {
return $fetch<T>(url, {
method: 'POST',
body: data,
timeout,
...options,
})
.catch(async (error) => {
let errorMessage = translator.translate('error.generic');
if (typeof error.data?.message === 'string') {
errorMessage = error.data.message;
}
if (typeof error.data?.error === 'string') {
errorMessage = translator.translate(error.data?.error);
// in case no translatable key was provided
if (errorMessage === undefined) {
errorMessage = error.data?.error;
}
}
await alert(errorMessage, 'danger');
throw new Error(`POST to ${url} failed: ${error.data?.error || 'unknown error'}`);
});
};
return {
alert,
confirm,
editor,
alertRaw,
postWithAlertOnError,
};
};