chore: fix and migrate unit tests to vitest
This commit is contained in:
@@ -22,6 +22,7 @@ DEPLOY_PRIME_URL="test"
|
|||||||
NEXTAUTH_SECRET="test"
|
NEXTAUTH_SECRET="test"
|
||||||
NEXT_PUBLIC_PUBLIC_URL="test"
|
NEXT_PUBLIC_PUBLIC_URL="test"
|
||||||
NEXTAUTH_URL="test"
|
NEXTAUTH_URL="test"
|
||||||
|
NODE_ENV="test"
|
||||||
REVALIDATE_SECRET="test"
|
REVALIDATE_SECRET="test"
|
||||||
SEAMLESS_LOGIN_DA="test"
|
SEAMLESS_LOGIN_DA="test"
|
||||||
SEAMLESS_LOGIN_DE="test"
|
SEAMLESS_LOGIN_DE="test"
|
||||||
@@ -52,4 +53,4 @@ NEXT_PUBLIC_SENTRY_ENVIRONMENT="test"
|
|||||||
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE="0"
|
NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE="0"
|
||||||
SITEMAP_SYNC_SECRET="test"
|
SITEMAP_SYNC_SECRET="test"
|
||||||
|
|
||||||
BRANCH="test"
|
BRANCH="test"
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithIntl() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
return <h1>{intl.formatMessage({
|
|
||||||
defaultMessage: "some value goes here",
|
|
||||||
description: {}
|
|
||||||
})}</h1>
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
const someId = 'someId'
|
|
||||||
const data = {
|
|
||||||
type: 'something'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: someId,
|
|
||||||
description: {}
|
|
||||||
})}
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: data.type,
|
|
||||||
description: {}
|
|
||||||
})}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{true ? intl.formatMessage({
|
|
||||||
defaultMessage: "Some true string",
|
|
||||||
description: {}
|
|
||||||
}) : intl.formatMessage({
|
|
||||||
defaultMessage: "Some false string",
|
|
||||||
description: {}
|
|
||||||
})}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
const variable = "some value"
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{intl.formatMessage({
|
|
||||||
defaultMessage: `String with {variable}`,
|
|
||||||
description: {}
|
|
||||||
}, { variable: variable })}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithIntl() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
return <h1>{intl.formatMessage({ id: "some value goes here" })}</h1>
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
const someId = 'someId'
|
|
||||||
const data = {
|
|
||||||
type: 'something'
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{intl.formatMessage({ id: someId })}
|
|
||||||
{intl.formatMessage({ id: data.type })}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{intl.formatMessage(
|
|
||||||
true ? { id: "Some true string" } : { id: "Some false string" }
|
|
||||||
)}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithTernaryInside() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
const variable = "some value"
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{intl.formatMessage({ id: `String with ${variable}` })}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Run the lokalise.ts through Jiti
|
|
||||||
|
|
||||||
import { fileURLToPath } from "node:url"
|
|
||||||
|
|
||||||
import createJiti from "jiti"
|
|
||||||
|
|
||||||
const lokalise = createJiti(fileURLToPath(import.meta.url))("./lokalise.ts")
|
|
||||||
|
|
||||||
lokalise.codemod([
|
|
||||||
"**/*.{ts,tsx}",
|
|
||||||
"!**/codemods/lokalise/**", // ignore itself
|
|
||||||
"!**/node_modules/**", // ignore node_modules
|
|
||||||
])
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
import { readFileSync } from "node:fs"
|
|
||||||
import { join } from "node:path"
|
|
||||||
|
|
||||||
import { describe, expect, test } from "@jest/globals"
|
|
||||||
import { IndentationText, Project } from "ts-morph"
|
|
||||||
|
|
||||||
import { processSourceFile } from "./lokalise"
|
|
||||||
|
|
||||||
describe("Lokalise codemod", () => {
|
|
||||||
test("serverComponent: intl.formatMessage with only id", () => {
|
|
||||||
const input = readFileSync(
|
|
||||||
join(__dirname, "./fixtures/serverComponentOnlyId.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const expected = readFileSync(
|
|
||||||
join(__dirname, "./expectations/serverComponentOnlyId.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const project = new Project({
|
|
||||||
manipulationSettings: {
|
|
||||||
indentationText: IndentationText.TwoSpaces,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const sourceFile = project.createSourceFile(
|
|
||||||
"./fixtures/serverComponent.tsx",
|
|
||||||
input
|
|
||||||
)
|
|
||||||
|
|
||||||
processSourceFile(sourceFile)
|
|
||||||
|
|
||||||
const result = sourceFile.getFullText()
|
|
||||||
|
|
||||||
expect(result).toBe(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("serverComponent: intl.formatMessage with ternary inside", () => {
|
|
||||||
const input = readFileSync(
|
|
||||||
join(__dirname, "./fixtures/serverComponentWithTernaryInside.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const expected = readFileSync(
|
|
||||||
join(__dirname, "./expectations/serverComponentWithTernaryInside.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const project = new Project({
|
|
||||||
manipulationSettings: {
|
|
||||||
indentationText: IndentationText.TwoSpaces,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const sourceFile = project.createSourceFile(
|
|
||||||
"./fixtures/serverComponentWithTernaryInside.tsx",
|
|
||||||
input
|
|
||||||
)
|
|
||||||
|
|
||||||
processSourceFile(sourceFile)
|
|
||||||
|
|
||||||
const result = sourceFile.getFullText()
|
|
||||||
expect(result).toBe(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("serverComponent: intl.formatMessage with variables", () => {
|
|
||||||
const input = readFileSync(
|
|
||||||
join(__dirname, "./fixtures/serverComponentWithVariables.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const expected = readFileSync(
|
|
||||||
join(__dirname, "./expectations/serverComponentWithVariables.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const project = new Project({
|
|
||||||
manipulationSettings: {
|
|
||||||
indentationText: IndentationText.TwoSpaces,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const sourceFile = project.createSourceFile(
|
|
||||||
"./fixtures/serverComponentWithVariables.tsx",
|
|
||||||
input
|
|
||||||
)
|
|
||||||
|
|
||||||
processSourceFile(sourceFile)
|
|
||||||
|
|
||||||
const result = sourceFile.getFullText()
|
|
||||||
expect(result).toBe(expected)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("serverComponent: intl.formatMessage with variable for id", () => {
|
|
||||||
const input = readFileSync(
|
|
||||||
join(__dirname, "./fixtures/serverComponentVariableId.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const expected = readFileSync(
|
|
||||||
join(__dirname, "./expectations/serverComponentVariableId.tsx"),
|
|
||||||
{
|
|
||||||
encoding: "utf-8",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const project = new Project({
|
|
||||||
manipulationSettings: {
|
|
||||||
indentationText: IndentationText.TwoSpaces,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const sourceFile = project.createSourceFile(
|
|
||||||
"./fixtures/serverComponentVariableId.tsx",
|
|
||||||
input
|
|
||||||
)
|
|
||||||
|
|
||||||
processSourceFile(sourceFile)
|
|
||||||
|
|
||||||
const result = sourceFile.getFullText()
|
|
||||||
expect(result).toBe(expected)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
import {
|
|
||||||
type Expression,
|
|
||||||
type Node,
|
|
||||||
type ObjectLiteralExpression,
|
|
||||||
Project,
|
|
||||||
type SourceFile,
|
|
||||||
ts,
|
|
||||||
} from "ts-morph"
|
|
||||||
|
|
||||||
export function codemod(paths: string) {
|
|
||||||
const project = new Project()
|
|
||||||
project.addSourceFilesAtPaths(paths)
|
|
||||||
|
|
||||||
project.getSourceFiles().forEach((file) => {
|
|
||||||
processSourceFile(file)
|
|
||||||
file.saveSync()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function processSourceFile(file: SourceFile): void {
|
|
||||||
file.getDescendantsOfKind(ts.SyntaxKind.CallExpression).forEach((call) => {
|
|
||||||
const expression = call.getExpression().getText()
|
|
||||||
|
|
||||||
if (expression === "intl.formatMessage") {
|
|
||||||
const formatMessageArgs = call.getArguments()
|
|
||||||
|
|
||||||
if (formatMessageArgs.length > 0) {
|
|
||||||
const firstFormatMessageArg = formatMessageArgs[0]
|
|
||||||
|
|
||||||
// Handle object literal in the first argument
|
|
||||||
if (
|
|
||||||
firstFormatMessageArg.getKind() ===
|
|
||||||
ts.SyntaxKind.ObjectLiteralExpression
|
|
||||||
) {
|
|
||||||
const expressionVariables = getVariableArguments(
|
|
||||||
firstFormatMessageArg.asKindOrThrow(
|
|
||||||
ts.SyntaxKind.ObjectLiteralExpression
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (expressionVariables === "{}") {
|
|
||||||
// No variables
|
|
||||||
transformObjectLiteral(
|
|
||||||
firstFormatMessageArg.asKindOrThrow(
|
|
||||||
ts.SyntaxKind.ObjectLiteralExpression
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Handle variables
|
|
||||||
const expressionReplacement = `intl.formatMessage(${transformObjectLiteralAndReturn(
|
|
||||||
firstFormatMessageArg.asKindOrThrow(
|
|
||||||
ts.SyntaxKind.ObjectLiteralExpression
|
|
||||||
)
|
|
||||||
)}, ${expressionVariables})`
|
|
||||||
|
|
||||||
call.replaceWithText(expressionReplacement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle ternary expressions in the first argument
|
|
||||||
else if (
|
|
||||||
firstFormatMessageArg.getKind() ===
|
|
||||||
ts.SyntaxKind.ConditionalExpression
|
|
||||||
) {
|
|
||||||
const conditional = firstFormatMessageArg.asKindOrThrow(
|
|
||||||
ts.SyntaxKind.ConditionalExpression
|
|
||||||
)
|
|
||||||
|
|
||||||
const whenTrue = conditional.getWhenTrue()
|
|
||||||
const whenFalse = conditional.getWhenFalse()
|
|
||||||
|
|
||||||
// Check for variables in message
|
|
||||||
const varArgsWhenTrue = getVariableArguments(whenTrue)
|
|
||||||
const varArgsWhenFalse = getVariableArguments(whenFalse)
|
|
||||||
|
|
||||||
// Replacements
|
|
||||||
const whenTrueReplacement =
|
|
||||||
varArgsWhenTrue !== "{}"
|
|
||||||
? `intl.formatMessage(${transformObjectLiteralAndReturn(whenTrue)}, ${varArgsWhenTrue})`
|
|
||||||
: `intl.formatMessage(${transformObjectLiteralAndReturn(whenTrue)})`
|
|
||||||
|
|
||||||
const whenFalseReplacement =
|
|
||||||
varArgsWhenFalse !== "{}"
|
|
||||||
? `intl.formatMessage(${transformObjectLiteralAndReturn(whenFalse)}, ${varArgsWhenFalse})`
|
|
||||||
: `intl.formatMessage(${transformObjectLiteralAndReturn(whenFalse)})`
|
|
||||||
|
|
||||||
// Replace the ternary expression
|
|
||||||
call.replaceWithText(
|
|
||||||
`${conditional.getCondition().getText()} ? ${whenTrueReplacement} : ${whenFalseReplacement}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Format the file using its existing formatting rules
|
|
||||||
file.formatText({
|
|
||||||
indentSize: 2,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to transform object literals
|
|
||||||
function transformObjectLiteral(objectLiteral: ObjectLiteralExpression): void {
|
|
||||||
const idProperty = objectLiteral
|
|
||||||
.getProperties()
|
|
||||||
.find((prop) => {
|
|
||||||
const p = prop.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
|
|
||||||
return p.getName() === "id"
|
|
||||||
})
|
|
||||||
?.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
|
|
||||||
|
|
||||||
if (idProperty) {
|
|
||||||
const idValue = idProperty.getInitializer()?.getText()
|
|
||||||
|
|
||||||
if (idValue) {
|
|
||||||
// Add defaultMessage
|
|
||||||
if (
|
|
||||||
!objectLiteral
|
|
||||||
.getProperties()
|
|
||||||
.some(
|
|
||||||
(prop) => "getName" in prop && prop.getName() === "defaultMessage"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
objectLiteral.addPropertyAssignment({
|
|
||||||
name: "defaultMessage",
|
|
||||||
initializer: idValue,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the id property
|
|
||||||
idProperty.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add description if not present
|
|
||||||
// if (
|
|
||||||
// !objectLiteral
|
|
||||||
// .getProperties()
|
|
||||||
// .some((prop) => "getName" in prop && prop.getName() === "description")
|
|
||||||
// ) {
|
|
||||||
// objectLiteral.addPropertyAssignment({
|
|
||||||
// name: "description",
|
|
||||||
// initializer: `{}`,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Extract variables from the defaultMessage if present
|
|
||||||
const defaultMessageProp = objectLiteral
|
|
||||||
.getProperties()
|
|
||||||
.find((prop) => "getName" in prop && prop.getName() === "defaultMessage")
|
|
||||||
?.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
|
|
||||||
|
|
||||||
if (defaultMessageProp) {
|
|
||||||
const defaultMessageValue = defaultMessageProp.getInitializer()?.getText()
|
|
||||||
|
|
||||||
if (defaultMessageValue) {
|
|
||||||
const extractedVariables =
|
|
||||||
extractVariablesFromTemplateString(defaultMessageValue)
|
|
||||||
if (extractedVariables.length > 0) {
|
|
||||||
// Replace the variables in the defaultMessage with FormatJS placeholders
|
|
||||||
const transformedMessage = replaceWithFormatJSPlaceholders(
|
|
||||||
defaultMessageValue,
|
|
||||||
extractedVariables
|
|
||||||
)
|
|
||||||
defaultMessageProp.setInitializer(`${transformedMessage}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to extract variables from a template string
|
|
||||||
function extractVariablesFromTemplateString(templateString: string): string[] {
|
|
||||||
const regex = /\${(.*?)}/g
|
|
||||||
const variables: string[] = []
|
|
||||||
let match
|
|
||||||
|
|
||||||
// Find all variable references in the template literal
|
|
||||||
while ((match = regex.exec(templateString)) !== null) {
|
|
||||||
variables.push(match[1].trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
return variables
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to replace variables with FormatJS placeholders
|
|
||||||
function replaceWithFormatJSPlaceholders(
|
|
||||||
templateString: string,
|
|
||||||
variables: string[]
|
|
||||||
): string {
|
|
||||||
let transformedMessage = templateString
|
|
||||||
|
|
||||||
variables.forEach((variable) => {
|
|
||||||
transformedMessage = transformedMessage.replace(
|
|
||||||
`\${${variable}}`,
|
|
||||||
`{${variable}}`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return transformedMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to get the variables from the ternary branch
|
|
||||||
function getVariableArguments(exp: Expression): string {
|
|
||||||
const idProp = exp
|
|
||||||
.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
|
|
||||||
.getProperties()
|
|
||||||
.find((prop) => "getName" in prop && prop.getName() === "id")
|
|
||||||
?.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
|
|
||||||
|
|
||||||
if (idProp) {
|
|
||||||
const extractedVariables = extractVariablesFromTemplateString(
|
|
||||||
idProp.getText()
|
|
||||||
)
|
|
||||||
if (extractedVariables.length > 0) {
|
|
||||||
return `{ ${extractedVariables.map((v) => `${v}: ${v}`).join(", ")} }`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "{}" // Return empty if no variables found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to transform object literals and return text
|
|
||||||
function transformObjectLiteralAndReturn(object: Node): string {
|
|
||||||
if (object.getKind() === ts.SyntaxKind.ObjectLiteralExpression) {
|
|
||||||
const obj = object.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression)
|
|
||||||
transformObjectLiteral(obj)
|
|
||||||
return obj.getText() // Return the transformed object literal as text
|
|
||||||
}
|
|
||||||
return object.getText()
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/* eslint-disable formatjs/enforce-description */
|
|
||||||
/* eslint-disable formatjs/enforce-default-message */
|
|
||||||
/* eslint-disable formatjs/no-id */
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
export default async function ServerComponentWithIntl() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
const variable = "some value"
|
|
||||||
|
|
||||||
return (
|
|
||||||
<h1>
|
|
||||||
{true
|
|
||||||
? intl.formatMessage({
|
|
||||||
defaultMessage: "Some string",
|
|
||||||
description: {},
|
|
||||||
})
|
|
||||||
: intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: `Other string {variable}`,
|
|
||||||
description: {},
|
|
||||||
},
|
|
||||||
{ variable: variable }
|
|
||||||
)}
|
|
||||||
</h1>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, it } from "@jest/globals"
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
import accessBooking, {
|
import accessBooking, {
|
||||||
ACCESS_GRANTED,
|
ACCESS_GRANTED,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { beforeAll, describe, expect, it } from "@jest/globals"
|
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
|
||||||
|
|
||||||
import { getValidFromDate, getValidToDate } from "./getValidDates"
|
import { getValidFromDate, getValidToDate } from "./getValidDates"
|
||||||
|
|
||||||
@@ -6,11 +6,11 @@ const NOW = new Date("2020-10-01T00:00:00Z")
|
|||||||
|
|
||||||
describe("getValidFromDate", () => {
|
describe("getValidFromDate", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
jest.useFakeTimers({ now: NOW })
|
vi.useFakeTimers({ now: NOW })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
jest.useRealTimers()
|
vi.useRealTimers()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("getValidFromDate", () => {
|
describe("getValidFromDate", () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, it } from "@jest/globals"
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
import { getGroupedOpeningHours } from "./utils"
|
import { getGroupedOpeningHours } from "./utils"
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ import type { IntlShape } from "react-intl"
|
|||||||
|
|
||||||
// Mock IntlShape for testing
|
// Mock IntlShape for testing
|
||||||
const mockIntl = {
|
const mockIntl = {
|
||||||
formatMessage: ({ id }: { id: string }) => {
|
formatMessage: ({ defaultMessage }: { defaultMessage: string }) => {
|
||||||
const messages: Record<string, string> = {
|
const messages: Record<string, string> = {
|
||||||
Monday: "Monday",
|
Monday: "Monday",
|
||||||
Tuesday: "Tuesday",
|
Tuesday: "Tuesday",
|
||||||
@@ -19,7 +19,7 @@ const mockIntl = {
|
|||||||
Closed: "Closed",
|
Closed: "Closed",
|
||||||
"Always open": "Always open",
|
"Always open": "Always open",
|
||||||
}
|
}
|
||||||
return messages[id] || id
|
return messages[defaultMessage] || defaultMessage
|
||||||
},
|
},
|
||||||
} as IntlShape
|
} as IntlShape
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,24 @@
|
|||||||
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
||||||
|
|
||||||
import { describe, expect, test } from "@jest/globals" // importing because of type conflict with globals from Cypress
|
import { User } from "@react-aria/test-utils"
|
||||||
import { render, screen } from "@testing-library/react"
|
import { userEvent } from "@testing-library/user-event"
|
||||||
import { type UserEvent, userEvent } from "@testing-library/user-event"
|
|
||||||
import { FormProvider, useForm } from "react-hook-form"
|
import { FormProvider, useForm } from "react-hook-form"
|
||||||
|
import { afterEach, describe, expect, test } from "vitest"
|
||||||
|
|
||||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
|
|
||||||
|
import { cleanup, render, screen } from "@/tests/utils"
|
||||||
import { getLocalizedMonthName } from "@/utils/dateFormatting"
|
import { getLocalizedMonthName } from "@/utils/dateFormatting"
|
||||||
|
|
||||||
import Date from "./index"
|
import Date from "./index"
|
||||||
|
|
||||||
jest.mock("react-intl", () => ({
|
const testUtilUser = new User({ interactionType: "touch" })
|
||||||
useIntl: () => ({
|
|
||||||
formatMessage: (message: { id: string }) => message.id,
|
|
||||||
formatNumber: (value: number) => value,
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
|
|
||||||
interface FormWrapperProps {
|
interface FormWrapperProps {
|
||||||
defaultValues: Record<string, unknown>
|
defaultValues: Record<string, unknown>
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
onSubmit: (data: unknown) => void
|
onSubmit: (event: unknown) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function FormWrapper({ defaultValues, children, onSubmit }: FormWrapperProps) {
|
function FormWrapper({ defaultValues, children, onSubmit }: FormWrapperProps) {
|
||||||
@@ -31,7 +27,7 @@ function FormWrapper({ defaultValues, children, onSubmit }: FormWrapperProps) {
|
|||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<form onSubmit={methods.handleSubmit((data) => onSubmit(data))}>
|
<form onSubmit={methods.handleSubmit(onSubmit)}>
|
||||||
{children}
|
{children}
|
||||||
<button type="submit">Submit</button>
|
<button type="submit">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -39,19 +35,13 @@ function FormWrapper({ defaultValues, children, onSubmit }: FormWrapperProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function selectOption(user: UserEvent, name: RegExp, value: string) {
|
function selectOption(name: string, value: string) {
|
||||||
// since its not a proper Select element selectOptions from userEvent doesn't work
|
const selectTester = testUtilUser.createTester("Select", {
|
||||||
const select = screen.queryByRole("button", { name })
|
root: screen.getByTestId(name),
|
||||||
if (select) {
|
interactionType: "touch",
|
||||||
await user.click(select)
|
})
|
||||||
|
|
||||||
const option = screen.queryByRole("option", { name: value })
|
selectTester.selectOption({ option: value })
|
||||||
if (option) {
|
|
||||||
await user.click(option)
|
|
||||||
} else {
|
|
||||||
await user.click(select) // click select again to close it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const testCases = [
|
const testCases = [
|
||||||
@@ -112,16 +102,19 @@ const testCases = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
describe("Date input", () => {
|
describe("Date input", () => {
|
||||||
|
afterEach(cleanup)
|
||||||
|
|
||||||
test.each(testCases)(
|
test.each(testCases)(
|
||||||
"$description",
|
"$description",
|
||||||
async ({ defaultValue, dateOfBirth, expectedOutput }) => {
|
async ({ defaultValue, dateOfBirth, expectedOutput }) => {
|
||||||
const user = userEvent.setup()
|
const user = userEvent.setup()
|
||||||
const handleSubmit = jest.fn()
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<FormWrapper
|
<FormWrapper
|
||||||
defaultValues={{ dateOfBirth: defaultValue }}
|
defaultValues={{ dateOfBirth: defaultValue }}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={(data) => {
|
||||||
|
expect(data).toEqual(expectedOutput)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Date name="dateOfBirth" />
|
<Date name="dateOfBirth" />
|
||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
@@ -132,16 +125,12 @@ describe("Date input", () => {
|
|||||||
const month = date.getMonth() + 1
|
const month = date.getMonth() + 1
|
||||||
const day = date.getDate()
|
const day = date.getDate()
|
||||||
|
|
||||||
await selectOption(user, /year/i, year.toString())
|
selectOption("year", year.toString())
|
||||||
await selectOption(user, /month/i, getLocalizedMonthName(month, Lang.en))
|
selectOption("month", getLocalizedMonthName(month, Lang.en))
|
||||||
await selectOption(user, /day/i, day.toString())
|
selectOption("day", day.toString())
|
||||||
|
|
||||||
const submitButton = screen.getByRole("button", { name: /submit/i })
|
const submitButton = screen.getByRole("button", { name: /submit/i })
|
||||||
await user.click(submitButton)
|
await user.click(submitButton)
|
||||||
|
|
||||||
expect(handleSubmit).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining(expectedOutput)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,212 +0,0 @@
|
|||||||
/**
|
|
||||||
* For a detailed explanation regarding each configuration property, visit:
|
|
||||||
* https://jestjs.io/docs/configuration
|
|
||||||
*/
|
|
||||||
import nextJest from "next/jest.js"
|
|
||||||
import { createJsWithTsEsmPreset } from "ts-jest"
|
|
||||||
|
|
||||||
import type { Config } from "jest"
|
|
||||||
|
|
||||||
const presetConfig = createJsWithTsEsmPreset()
|
|
||||||
|
|
||||||
const createJestConfig = nextJest({
|
|
||||||
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
|
|
||||||
dir: "./",
|
|
||||||
})
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
// All imported modules in your tests should be mocked automatically
|
|
||||||
// automock: false,
|
|
||||||
|
|
||||||
// Stop running tests after `n` failures
|
|
||||||
// bail: 0,
|
|
||||||
|
|
||||||
// The directory where Jest should store its cached dependency information
|
|
||||||
// cacheDirectory: "/private/var/folders/v8/61rbfxwx3jddjj8z_qxgm_tc0000gn/T/jest_dx",
|
|
||||||
|
|
||||||
// Automatically clear mock calls, instances, contexts and results before every test
|
|
||||||
clearMocks: true,
|
|
||||||
|
|
||||||
// Indicates whether the coverage information should be collected while executing the test
|
|
||||||
// collectCoverage: false,
|
|
||||||
|
|
||||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
|
||||||
// collectCoverageFrom: undefined,
|
|
||||||
|
|
||||||
// The directory where Jest should output its coverage files
|
|
||||||
// coverageDirectory: undefined,
|
|
||||||
|
|
||||||
// An array of regexp pattern strings used to skip coverage collection
|
|
||||||
// coveragePathIgnorePatterns: [
|
|
||||||
// "/node_modules/"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// Indicates which provider should be used to instrument code for coverage
|
|
||||||
coverageProvider: "v8",
|
|
||||||
|
|
||||||
// A list of reporter names that Jest uses when writing coverage reports
|
|
||||||
// coverageReporters: [
|
|
||||||
// "json",
|
|
||||||
// "text",
|
|
||||||
// "lcov",
|
|
||||||
// "clover"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An object that configures minimum threshold enforcement for coverage results
|
|
||||||
// coverageThreshold: undefined,
|
|
||||||
|
|
||||||
// A path to a custom dependency extractor
|
|
||||||
// dependencyExtractor: undefined,
|
|
||||||
|
|
||||||
// Make calling deprecated APIs throw helpful error messages
|
|
||||||
// errorOnDeprecated: false,
|
|
||||||
|
|
||||||
// The default configuration for fake timers
|
|
||||||
// fakeTimers: {
|
|
||||||
// "enableGlobally": false
|
|
||||||
// },
|
|
||||||
|
|
||||||
// Force coverage collection from ignored files using an array of glob patterns
|
|
||||||
// forceCoverageMatch: [],
|
|
||||||
|
|
||||||
// A path to a module which exports an async function that is triggered once before all test suites
|
|
||||||
// globalSetup: undefined,
|
|
||||||
|
|
||||||
// A path to a module which exports an async function that is triggered once after all test suites
|
|
||||||
// globalTeardown: undefined,
|
|
||||||
|
|
||||||
// A set of global variables that need to be available in all test environments
|
|
||||||
// globals: {},
|
|
||||||
|
|
||||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
|
||||||
// maxWorkers: "50%",
|
|
||||||
|
|
||||||
// An array of directory names to be searched recursively up from the requiring module's location
|
|
||||||
// moduleDirectories: [
|
|
||||||
// "node_modules"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of file extensions your modules use
|
|
||||||
// moduleFileExtensions: [
|
|
||||||
// "js",
|
|
||||||
// "mjs",
|
|
||||||
// "cjs",
|
|
||||||
// "jsx",
|
|
||||||
// "ts",
|
|
||||||
// "tsx",
|
|
||||||
// "json",
|
|
||||||
// "node"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
|
||||||
moduleNameMapper: {
|
|
||||||
"^@/(.*)$": "<rootDir>/$1",
|
|
||||||
},
|
|
||||||
|
|
||||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
|
||||||
// modulePathIgnorePatterns: [],
|
|
||||||
|
|
||||||
// Activates notifications for test results
|
|
||||||
// notify: false,
|
|
||||||
|
|
||||||
// An enum that specifies notification mode. Requires { notify: true }
|
|
||||||
// notifyMode: "failure-change",
|
|
||||||
|
|
||||||
// A preset that is used as a base for Jest's configuration
|
|
||||||
// preset: undefined,
|
|
||||||
|
|
||||||
// Run tests from one or more projects
|
|
||||||
// projects: undefined,
|
|
||||||
|
|
||||||
// Use this configuration option to add custom reporters to Jest
|
|
||||||
// reporters: undefined,
|
|
||||||
|
|
||||||
// Automatically reset mock state before every test
|
|
||||||
// resetMocks: false,
|
|
||||||
|
|
||||||
// Reset the module registry before running each individual test
|
|
||||||
// resetModules: false,
|
|
||||||
|
|
||||||
// A path to a custom resolver
|
|
||||||
// resolver: undefined,
|
|
||||||
|
|
||||||
// Automatically restore mock state and implementation before every test
|
|
||||||
// restoreMocks: false,
|
|
||||||
|
|
||||||
// The root directory that Jest should scan for tests and modules within
|
|
||||||
// rootDir: undefined,
|
|
||||||
|
|
||||||
// A list of paths to directories that Jest should use to search for files in
|
|
||||||
// roots: [
|
|
||||||
// "<rootDir>"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// Allows you to use a custom runner instead of Jest's default test runner
|
|
||||||
// runner: "jest-runner",
|
|
||||||
|
|
||||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
|
||||||
// setupFiles: [],
|
|
||||||
|
|
||||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
|
||||||
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
|
|
||||||
|
|
||||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
|
||||||
// slowTestThreshold: 5,
|
|
||||||
|
|
||||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
|
||||||
// snapshotSerializers: [],
|
|
||||||
|
|
||||||
// The test environment that will be used for testing
|
|
||||||
testEnvironment: "jest-environment-jsdom",
|
|
||||||
|
|
||||||
// Options that will be passed to the testEnvironment
|
|
||||||
// testEnvironmentOptions: {},
|
|
||||||
|
|
||||||
// Adds a location field to test results
|
|
||||||
// testLocationInResults: false,
|
|
||||||
|
|
||||||
// The glob patterns Jest uses to detect test files
|
|
||||||
// testMatch: [
|
|
||||||
// "**/__tests__/**/*.[jt]s?(x)",
|
|
||||||
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
|
||||||
// testPathIgnorePatterns: [
|
|
||||||
// "/node_modules/"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
|
||||||
// testRegex: [],
|
|
||||||
|
|
||||||
// This option allows the use of a custom results processor
|
|
||||||
// testResultsProcessor: undefined,
|
|
||||||
|
|
||||||
// This option allows use of a custom test runner
|
|
||||||
// testRunner: "jest-circus/runner",
|
|
||||||
|
|
||||||
// A map from regular expressions to paths to transformers
|
|
||||||
// transform: undefined,
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
|
||||||
// transformIgnorePatterns: [
|
|
||||||
// "/node_modules/",
|
|
||||||
// "\\.pnp\\.[^\\/]+$"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
|
||||||
// unmockedModulePathPatterns: undefined,
|
|
||||||
|
|
||||||
// Indicates whether each individual test should be reported during the run
|
|
||||||
// verbose: undefined,
|
|
||||||
|
|
||||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
|
||||||
// watchPathIgnorePatterns: [],
|
|
||||||
|
|
||||||
// Whether to use watchman for file crawling
|
|
||||||
// watchman: true,
|
|
||||||
|
|
||||||
...presetConfig,
|
|
||||||
} satisfies Config
|
|
||||||
|
|
||||||
export default createJestConfig(config)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import "@testing-library/jest-dom/jest-globals"
|
|
||||||
import "@testing-library/jest-dom"
|
|
||||||
|
|
||||||
import { jest } from "@jest/globals"
|
|
||||||
|
|
||||||
jest.mock("next/navigation", () => ({
|
|
||||||
useRouter: jest.fn(),
|
|
||||||
usePathname: jest.fn().mockReturnValue("/"),
|
|
||||||
useParams: jest.fn().mockReturnValue({ lang: "en" }),
|
|
||||||
}))
|
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
"test:e2e:headless": "start-server-and-test test:setup http://127.0.0.1:3000/en/sponsoring \"cypress run --e2e\"",
|
"test:e2e:headless": "start-server-and-test test:setup http://127.0.0.1:3000/en/sponsoring \"cypress run --e2e\"",
|
||||||
"test:setup": "yarn build && yarn start",
|
"test:setup": "yarn build && yarn start",
|
||||||
"preinstall": "/bin/sh -c \"export $(cat .env.local | grep -v '^#' | xargs)\"",
|
"preinstall": "/bin/sh -c \"export $(cat .env.local | grep -v '^#' | xargs)\"",
|
||||||
"test": "node --experimental-vm-modules $(yarn bin jest)",
|
"test": "vitest run",
|
||||||
"test:watch": "node --experimental-vm-modules $(yarn bin jest) --watch",
|
"test:watch": "vitest",
|
||||||
"ci:build": "yarn lint && yarn test && yarn build",
|
"ci:build": "yarn lint && yarn test && yarn build",
|
||||||
"clean": "rm -rf .next",
|
"clean": "rm -rf .next",
|
||||||
"i18n:extract": "formatjs extract \"{actions,app,components,constants,contexts,env,hooks,i18n,lib,middlewares,netlify,providers,server,services,stores,utils}/**/*.{ts,tsx}\" --format i18n/tooling/formatter.mjs --out-file i18n/tooling/extracted.json",
|
"i18n:extract": "formatjs extract \"{actions,app,components,constants,contexts,env,hooks,i18n,lib,middlewares,netlify,providers,server,services,stores,utils}/**/*.{ts,tsx}\" --format i18n/tooling/formatter.mjs --out-file i18n/tooling/extracted.json",
|
||||||
@@ -120,14 +120,13 @@
|
|||||||
"@eslint/js": "^9.26.0",
|
"@eslint/js": "^9.26.0",
|
||||||
"@formatjs/cli": "^6.7.1",
|
"@formatjs/cli": "^6.7.1",
|
||||||
"@lokalise/node-api": "^14.0.0",
|
"@lokalise/node-api": "^14.0.0",
|
||||||
|
"@react-aria/test-utils": "1.0.0-alpha.8",
|
||||||
"@scandic-hotels/common": "workspace:*",
|
"@scandic-hotels/common": "workspace:*",
|
||||||
"@scandic-hotels/typescript-config": "workspace:*",
|
"@scandic-hotels/typescript-config": "workspace:*",
|
||||||
"@svgr/webpack": "^8.1.0",
|
"@svgr/webpack": "^8.1.0",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/adm-zip": "^0.5.7",
|
"@types/adm-zip": "^0.5.7",
|
||||||
"@types/jest": "^29.5.14",
|
|
||||||
"@types/json-stable-stringify-without-jsonify": "^1.0.2",
|
"@types/json-stable-stringify-without-jsonify": "^1.0.2",
|
||||||
"@types/jsonwebtoken": "^9",
|
"@types/jsonwebtoken": "^9",
|
||||||
"@types/lodash-es": "^4",
|
"@types/lodash-es": "^4",
|
||||||
@@ -136,7 +135,9 @@
|
|||||||
"@types/react-dom": "19.1.0",
|
"@types/react-dom": "19.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
||||||
"@typescript-eslint/parser": "^8.32.0",
|
"@typescript-eslint/parser": "^8.32.0",
|
||||||
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
|
"babel-plugin-formatjs": "^10.5.39",
|
||||||
"cypress": "^14.3.3",
|
"cypress": "^14.3.3",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
@@ -144,20 +145,20 @@
|
|||||||
"eslint-plugin-formatjs": "^5.3.1",
|
"eslint-plugin-formatjs": "^5.3.1",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"jest": "^29.7.0",
|
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
|
||||||
"jiti": "^1.21.0",
|
"jiti": "^1.21.0",
|
||||||
|
"jsdom": "^26.1.0",
|
||||||
"json-sort-cli": "^4.0.9",
|
"json-sort-cli": "^4.0.9",
|
||||||
"lint-staged": "^15.5.2",
|
"lint-staged": "^15.5.2",
|
||||||
"netlify-plugin-cypress": "^2.2.1",
|
"netlify-plugin-cypress": "^2.2.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"schema-dts": "^1.1.5",
|
"schema-dts": "^1.1.5",
|
||||||
"start-server-and-test": "^2.0.11",
|
"start-server-and-test": "^2.0.11",
|
||||||
"ts-jest": "^29.3.2",
|
|
||||||
"ts-morph": "^25.0.1",
|
"ts-morph": "^25.0.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "5.8.3",
|
"typescript": "5.8.3",
|
||||||
"typescript-plugin-css-modules": "^5.1.0"
|
"typescript-plugin-css-modules": "^5.1.0",
|
||||||
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "22"
|
"node": "22"
|
||||||
|
|||||||
27
apps/scandic-web/tests/utils.tsx
Normal file
27
apps/scandic-web/tests/utils.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { render, type RenderOptions } from "@testing-library/react"
|
||||||
|
import React, { type ReactElement } from "react"
|
||||||
|
|
||||||
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
|
||||||
|
import messages from "@/i18n/dictionaries/en.json"
|
||||||
|
import ClientIntlProvider from "@/i18n/Provider"
|
||||||
|
|
||||||
|
function AllTheProviders({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ClientIntlProvider
|
||||||
|
defaultLocale={Lang.en}
|
||||||
|
locale={Lang.en}
|
||||||
|
messages={messages}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ClientIntlProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const customRender = (
|
||||||
|
ui: ReactElement,
|
||||||
|
options?: Omit<RenderOptions, "wrapper">
|
||||||
|
) => render(ui, { wrapper: AllTheProviders, ...options })
|
||||||
|
|
||||||
|
export * from "@testing-library/react"
|
||||||
|
export { customRender as render }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, test } from "@jest/globals"
|
import { describe, expect, test } from "vitest"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import { parseSearchParams, serializeSearchParams } from "./searchParams"
|
import { parseSearchParams, serializeSearchParams } from "./searchParams"
|
||||||
|
|||||||
30
apps/scandic-web/vitest-setup.ts
Normal file
30
apps/scandic-web/vitest-setup.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { vi } from "vitest"
|
||||||
|
|
||||||
|
process.env.TZ = "UTC"
|
||||||
|
|
||||||
|
vi.mock("next/navigation", () => ({
|
||||||
|
useRouter: vi.fn(),
|
||||||
|
usePathname: vi.fn().mockReturnValue("/"),
|
||||||
|
useParams: vi.fn().mockReturnValue({ lang: "en" }),
|
||||||
|
}))
|
||||||
|
|
||||||
|
Object.defineProperty(window, "matchMedia", {
|
||||||
|
writable: true,
|
||||||
|
value: vi.fn().mockImplementation((query) => ({
|
||||||
|
matches: false,
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: vi.fn(), // deprecated
|
||||||
|
removeListener: vi.fn(), // deprecated
|
||||||
|
addEventListener: vi.fn(),
|
||||||
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn(),
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(window, "CSS", {
|
||||||
|
writable: true,
|
||||||
|
value: {
|
||||||
|
escape: vi.fn(),
|
||||||
|
},
|
||||||
|
})
|
||||||
25
apps/scandic-web/vitest.config.js
Normal file
25
apps/scandic-web/vitest.config.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import react from "@vitejs/plugin-react"
|
||||||
|
import tsconfigPaths from "vite-tsconfig-paths"
|
||||||
|
import { defineConfig } from "vitest/config"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
tsconfigPaths(),
|
||||||
|
react({
|
||||||
|
babel: {
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
"formatjs",
|
||||||
|
{
|
||||||
|
idInterpolationPattern: "[sha512:contenthash:base64:6]",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
test: {
|
||||||
|
environment: "jsdom",
|
||||||
|
setupFiles: ["./vitest-setup.ts"],
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -28,18 +28,17 @@ describe("getSearchTokens", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = getSearchTokens(location as Location)
|
const result = getSearchTokens(location as Location)
|
||||||
expect(result.toSorted()).toEqual(
|
|
||||||
[
|
expect(result).toEqual([
|
||||||
"ångström",
|
"angstrom",
|
||||||
"café",
|
"cafe",
|
||||||
"münchen",
|
"munchen",
|
||||||
"frånce",
|
"france",
|
||||||
"angstrom",
|
"ångström",
|
||||||
"cafe",
|
"café",
|
||||||
"munchen",
|
"münchen",
|
||||||
"france",
|
"frånce",
|
||||||
].toSorted()
|
])
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should filter out empty or falsey tokens", () => {
|
it("should filter out empty or falsey tokens", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user