From 27eb2d43048b04dc006d1a99258d69ffa3151e98 Mon Sep 17 00:00:00 2001 From: Wenzhao Hu Date: Wed, 13 Nov 2024 12:03:03 +0800 Subject: [PATCH] test: add formula integration test (#4019) --- examples-node/package.json | 6 +- examples-node/src/cases/basic.ts | 2 - examples-node/src/index.ts | 17 +++ examples-node/src/sdk/index.ts | 21 ++- pnpm-lock.yaml | 49 +++++++ pnpm-workspace.yaml | 1 + tests/formula-integration/README.md | 3 + tests/formula-integration/build.ts | 19 +++ tests/formula-integration/package.json | 31 +++++ ...ormula-correctness---basic-sum-result.json | 120 +++++++++++++++++ .../test-formula-correctness---basic-sum.json | 123 ++++++++++++++++++ .../src/__testing__/univer.ts | 29 +++++ .../src/__testing__/util.ts | 67 ++++++++++ .../src/__tests__/formua-correctness.spec.ts | 24 ++++ tests/formula-integration/src/index.ts | 17 +++ tests/formula-integration/tsconfig.json | 9 ++ tests/formula-integration/tsconfig.node.json | 4 + tests/formula-integration/vitest.config.ts | 3 + 18 files changed, 537 insertions(+), 8 deletions(-) create mode 100644 examples-node/src/index.ts create mode 100644 tests/formula-integration/README.md create mode 100644 tests/formula-integration/build.ts create mode 100644 tests/formula-integration/package.json create mode 100644 tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum-result.json create mode 100644 tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum.json create mode 100644 tests/formula-integration/src/__testing__/univer.ts create mode 100644 tests/formula-integration/src/__testing__/util.ts create mode 100644 tests/formula-integration/src/__tests__/formua-correctness.spec.ts create mode 100644 tests/formula-integration/src/index.ts create mode 100644 tests/formula-integration/tsconfig.json create mode 100644 tests/formula-integration/tsconfig.node.json create mode 100644 tests/formula-integration/vitest.config.ts diff --git a/examples-node/package.json b/examples-node/package.json index 9092111ff6..6c73a9ac52 100644 --- a/examples-node/package.json +++ b/examples-node/package.json @@ -1,9 +1,13 @@ { - "name": "univer-examples-node", + "name": "examples-node", "private": true, "description": "Examples run on Node.js", "author": "DreamNum ", "license": "Apache-2.0", + "exports": { + ".": "./src/index.ts", + "./*": "./src/*" + }, "scripts": { "build:demo": "node ./esbuild.config.mjs", "lint:types": "node ./scripts/generate-locales.mjs && tsc --noEmit" diff --git a/examples-node/src/cases/basic.ts b/examples-node/src/cases/basic.ts index 05953b4416..6918231d29 100644 --- a/examples-node/src/cases/basic.ts +++ b/examples-node/src/cases/basic.ts @@ -18,8 +18,6 @@ import process from 'node:process'; import { awaitTime, FUniver } from '@univerjs/core'; import { createUniverOnNode } from '../sdk'; -import '../sdk/facade'; - // From now on, Univer is a full-stack SDK. async function run(): Promise { diff --git a/examples-node/src/index.ts b/examples-node/src/index.ts new file mode 100644 index 0000000000..a9af8a9f2c --- /dev/null +++ b/examples-node/src/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { createUniverOnNode, type ICreateUniverOnNodeOptions } from './sdk'; diff --git a/examples-node/src/sdk/index.ts b/examples-node/src/sdk/index.ts index 4779c67a67..5153f4f893 100644 --- a/examples-node/src/sdk/index.ts +++ b/examples-node/src/sdk/index.ts @@ -32,12 +32,23 @@ import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'; import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'; import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'; -export function createUniverOnNode(): Univer { +import './facade'; + +export interface ICreateUniverOnNodeOptions { + useComputingWorker?: boolean; +} + +export function createUniverOnNode(options: ICreateUniverOnNodeOptions = {}): Univer { + const { useComputingWorker = false } = options; + const univer = new Univer(); - registerBasicPlugins(univer); + registerBasicPlugins(univer, useComputingWorker); registerSharedPlugins(univer); - registerRPCPlugin(univer); + + if (useComputingWorker) { + registerRPCPlugin(univer); + } registerDocPlugins(univer); registerSheetPlugins(univer); @@ -45,8 +56,8 @@ export function createUniverOnNode(): Univer { return univer; } -function registerBasicPlugins(univer: Univer): void { - univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: true }); +function registerBasicPlugins(univer: Univer, useComputingWorker: boolean): void { + univer.registerPlugin(UniverFormulaEnginePlugin, { notExecuteFormula: useComputingWorker }); } function registerSharedPlugins(univer: Univer): void { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99d93e2a33..08603343ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3456,6 +3456,55 @@ importers: specifier: ^2.1.4 version: 2.1.4(@types/node@22.9.0)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + tests/formula-integration: + dependencies: + '@univerjs/core': + specifier: workspace:* + version: link:../../packages/core + '@univerjs/data-validation': + specifier: workspace:* + version: link:../../packages/data-validation + '@univerjs/docs': + specifier: workspace:* + version: link:../../packages/docs + '@univerjs/engine-formula': + specifier: workspace:* + version: link:../../packages/engine-formula + '@univerjs/mockdata': + specifier: workspace:* + version: link:../../mockdata + '@univerjs/rpc': + specifier: workspace:* + version: link:../../packages/rpc + '@univerjs/sheets': + specifier: workspace:* + version: link:../../packages/sheets + '@univerjs/sheets-conditional-formatting': + specifier: workspace:* + version: link:../../packages/sheets-conditional-formatting + '@univerjs/sheets-data-validation': + specifier: workspace:* + version: link:../../packages/sheets-data-validation + '@univerjs/sheets-formula': + specifier: workspace:* + version: link:../../packages/sheets-formula + '@univerjs/sheets-numfmt': + specifier: workspace:* + version: link:../../packages/sheets-numfmt + examples-node: + specifier: workspace:* + version: link:../../examples-node + devDependencies: + '@univerjs-infra/shared': + specifier: workspace:* + version: link:../../common/shared + typescript: + specifier: ^5.6.3 + version: 5.6.3 + vitest: + specifier: ^2.1.4 + version: 2.1.4(@types/node@22.9.0)(happy-dom@15.0.0)(jsdom@24.1.1)(less@4.2.0)(sass@1.77.5)(terser@5.31.6) + packages: '@adobe/css-tools@4.4.0': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bc7a8af184..ba324b1bd0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,3 +5,4 @@ packages: - mockdata - packages-experimental/* - packages/* + - tests/* diff --git a/tests/formula-integration/README.md b/tests/formula-integration/README.md new file mode 100644 index 0000000000..7d7a8e1fb8 --- /dev/null +++ b/tests/formula-integration/README.md @@ -0,0 +1,3 @@ +# formula-integration-test + +This is a test repository for the formula integration feature. It also exports some util functions that can be used in the advanced formula engine integration test. diff --git a/tests/formula-integration/build.ts b/tests/formula-integration/build.ts new file mode 100644 index 0000000000..cdb3dc98ea --- /dev/null +++ b/tests/formula-integration/build.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { build } from '@univerjs-infra/shared/vite'; + +build(); diff --git a/tests/formula-integration/package.json b/tests/formula-integration/package.json new file mode 100644 index 0000000000..4f05457f0c --- /dev/null +++ b/tests/formula-integration/package.json @@ -0,0 +1,31 @@ +{ + "name": "formula-integration-test", + "private": true, + "author": "DreamNum ", + "license": "Apache-2.0", + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "coverage": "vitest run --coverage", + "lint:types": "tsc --noEmit" + }, + "dependencies": { + "@univerjs/core": "workspace:*", + "@univerjs/data-validation": "workspace:*", + "@univerjs/docs": "workspace:*", + "@univerjs/engine-formula": "workspace:*", + "@univerjs/mockdata": "workspace:*", + "@univerjs/rpc": "workspace:*", + "@univerjs/sheets": "workspace:*", + "@univerjs/sheets-conditional-formatting": "workspace:*", + "@univerjs/sheets-data-validation": "workspace:*", + "@univerjs/sheets-formula": "workspace:*", + "@univerjs/sheets-numfmt": "workspace:*", + "examples-node": "workspace:*" + }, + "devDependencies": { + "@univerjs-infra/shared": "workspace:*", + "typescript": "^5.6.3", + "vitest": "^2.1.4" + } +} diff --git a/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum-result.json b/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum-result.json new file mode 100644 index 0000000000..1439339abd --- /dev/null +++ b/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum-result.json @@ -0,0 +1,120 @@ +{ + "id": "-23yFfY3SZ2pr9nPYERZXg", + "sheetOrder": [ + "4FDtSTxrsa_03719b8_jm" + ], + "name": "New Sheet", + "appVersion": "1", + "locale": "enUS", + "styles": { + "1l4gGD": { + "ff": "Arial", + "fs": 11 + } + }, + "sheets": { + "4FDtSTxrsa_03719b8_jm": { + "id": "4FDtSTxrsa_03719b8_jm", + "name": "Sheet1", + "rowCount": 1000, + "columnCount": 20, + "freeze": { + "xSplit": 0, + "ySplit": 0, + "startRow": -1, + "startColumn": -1 + }, + "hidden": 0, + "rowData": { + "0": { + "ah": 24 + }, + "1": { + "ah": 24 + } + }, + "tabColor": "", + "mergeData": [], + "rowHeader": { + "width": 46, + "hidden": 0 + }, + "scrollTop": 200, + "zoomRatio": 1, + "columnData": {}, + "scrollLeft": 100, + "rightToLeft": 0, + "columnHeader": { + "height": 20, + "hidden": 0 + }, + "showGridlines": 1, + "defaultRowHeight": 24, + "defaultColumnWidth": 88, + "cellData": { + "0": { + "0": { + "v": 1, + "t": 2, + "s": "1l4gGD" + }, + "1": { + "f": "=SUM(A1:A2)", + "t": 2, + "v": 3 + } + }, + "1": { + "0": { + "v": 2, + "t": 2, + "s": "1l4gGD" + } + } + } + } + }, + "resources": [ + { + "name": "SHEET_UNIVER_THREAD_COMMENT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_RANGE_PROTECTION_PLUGIN", + "data": "" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_POINT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_CONDITIONAL_FORMATTING_PLUGIN", + "data": "" + }, + { + "name": "SHEET_HYPER_LINK_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DRAWING_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DEFINED_NAME_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DATA_VALIDATION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_FILTER_PLUGIN", + "data": "{}" + } + ], + "rev": 4 +} \ No newline at end of file diff --git a/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum.json b/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum.json new file mode 100644 index 0000000000..5b15d4648f --- /dev/null +++ b/tests/formula-integration/src/__snapshots__/test-formula-correctness---basic-sum.json @@ -0,0 +1,123 @@ +{ + "id": "-23yFfY3SZ2pr9nPYERZXg", + "sheetOrder": [ + "4FDtSTxrsa_03719b8_jm" + ], + "name": "New Sheet", + "appVersion": "1", + "locale": "enUS", + "styles": { + "1l4gGD": { + "ff": "Arial", + "fs": 11 + } + }, + "sheets": { + "4FDtSTxrsa_03719b8_jm": { + "id": "4FDtSTxrsa_03719b8_jm", + "name": "Sheet1", + "rowCount": 1000, + "columnCount": 20, + "freeze": { + "xSplit": 0, + "ySplit": 0, + "startRow": -1, + "startColumn": -1 + }, + "hidden": 0, + "rowData": { + "0": { + "ah": 24 + }, + "1": { + "ah": 24 + } + }, + "tabColor": "", + "mergeData": [], + "rowHeader": { + "width": 46, + "hidden": 0 + }, + "scrollTop": 200, + "zoomRatio": 1, + "columnData": {}, + "scrollLeft": 100, + "rightToLeft": 0, + "columnHeader": { + "height": 20, + "hidden": 0 + }, + "showGridlines": 1, + "defaultRowHeight": 24, + "defaultColumnWidth": 88, + "cellData": { + "0": { + "0": { + "v": 1, + "t": 2, + "s": "1l4gGD" + }, + "1": { + "f": "=SUM(A1:A2)", + "t": 2 + } + }, + "1": { + "0": { + "v": 2, + "t": 2, + "s": "1l4gGD" + } + } + } + } + }, + "resources": [ + { + "name": "SHEET_UNIVER_THREAD_COMMENT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_RANGE_PROTECTION_PLUGIN", + "data": "" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_WORKSHEET_PROTECTION_POINT_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_CONDITIONAL_FORMATTING_PLUGIN", + "data": "" + }, + { + "name": "SHEET_DRAWING_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_CHART_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_DEFINED_NAME_PLUGIN", + "data": "" + }, + { + "name": "SHEET_DATA_VALIDATION_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_FILTER_PLUGIN", + "data": "{}" + }, + { + "name": "SHEET_HYPER_LINK_PLUGIN", + "data": "{\"4FDtSTxrsa_03719b8_jm\":[]}" + } + ], + "rev": 4 +} diff --git a/tests/formula-integration/src/__testing__/univer.ts b/tests/formula-integration/src/__testing__/univer.ts new file mode 100644 index 0000000000..ca5f9b5ac9 --- /dev/null +++ b/tests/formula-integration/src/__testing__/univer.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FUniver } from '@univerjs/core'; +import { createUniverOnNode } from 'examples-node'; + +export function createFormulaTestBed() { + const univer = createUniverOnNode(); + const injector = univer.__getInjector(); + + return { + univer, + get: injector.get.bind(injector), + api: FUniver.newAPI(univer), + }; +} diff --git a/tests/formula-integration/src/__testing__/util.ts b/tests/formula-integration/src/__testing__/util.ts new file mode 100644 index 0000000000..9d35836729 --- /dev/null +++ b/tests/formula-integration/src/__testing__/util.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { IWorkbookData } from '@univerjs/core'; +import fs from 'node:fs'; +import path from 'node:path'; +import { expect } from 'vitest'; +import { createFormulaTestBed } from './univer'; + +function getTestName(): string { + const testName = expect.getState().currentTestName; + if (!testName) { + throw new Error('Cannot get test name. Maybe you call the method outside a test case?'); + } + + return testName; +} + +export function getTestFilePath() { + const name = getTestName(); + return name.replace(/[ >]/g, '-').toLowerCase(); +} + +/** + * + */ +export async function expectCalculationResultMatchesSnapshot() { + const testBed = createFormulaTestBed(); + const snapshotRootDir = path.join(import.meta.dirname, '../__snapshots__'); + + const testSnapshotPath = path.resolve(snapshotRootDir, `${getTestFilePath()}.json`); + if (!fs.existsSync(testSnapshotPath)) { + throw new Error(`Cannot find snapshot file for test "${getTestName()}".`); + } + + const testSnapshotRaw = fs.readFileSync(testSnapshotPath, 'utf-8'); + const testSnapshot = JSON.parse(testSnapshotRaw) as IWorkbookData; + + const workbook = testBed.api.createUniverSheet(testSnapshot); + const formula = testBed.api.getFormula(); + await formula.onCalculationEnd(); + + const resultSnapshot = workbook.save(); + const snapshotFilePath = path.resolve(snapshotRootDir, `${getTestFilePath()}-result.json`); + if (fs.existsSync(snapshotFilePath)) { + const resultSnapshotFileString = fs.readFileSync(snapshotFilePath, 'utf-8'); + expect(resultSnapshot).toMatchObject(JSON.parse(resultSnapshotFileString)); + } else { + fs.writeFileSync(snapshotFilePath, JSON.stringify(resultSnapshot, null, 4)); + + // eslint-disable-next-line no-console + console.log(`Snapshot file created at: ${snapshotFilePath}`); + } +} diff --git a/tests/formula-integration/src/__tests__/formua-correctness.spec.ts b/tests/formula-integration/src/__tests__/formua-correctness.spec.ts new file mode 100644 index 0000000000..a4a92156d7 --- /dev/null +++ b/tests/formula-integration/src/__tests__/formua-correctness.spec.ts @@ -0,0 +1,24 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it } from 'vitest'; +import { expectCalculationResultMatchesSnapshot } from '../__testing__/util'; + +describe('Test formula correctness', () => { + it('basic sum', () => { + expectCalculationResultMatchesSnapshot(); + }); +}); diff --git a/tests/formula-integration/src/index.ts b/tests/formula-integration/src/index.ts new file mode 100644 index 0000000000..84dad36ec1 --- /dev/null +++ b/tests/formula-integration/src/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2023-present DreamNum Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { expectCalculationResultMatchesSnapshot } from './__testing__/util'; diff --git a/tests/formula-integration/tsconfig.json b/tests/formula-integration/tsconfig.json new file mode 100644 index 0000000000..c62210cbad --- /dev/null +++ b/tests/formula-integration/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@univerjs-infra/shared/tsconfigs/base", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "references": [{ "path": "./tsconfig.node.json" }], + "include": ["src"] +} diff --git a/tests/formula-integration/tsconfig.node.json b/tests/formula-integration/tsconfig.node.json new file mode 100644 index 0000000000..7818f253cc --- /dev/null +++ b/tests/formula-integration/tsconfig.node.json @@ -0,0 +1,4 @@ +{ + "extends": "@univerjs-infra/shared/tsconfigs/node", + "include": ["vitest.config.ts", "build.ts"] +} diff --git a/tests/formula-integration/vitest.config.ts b/tests/formula-integration/vitest.config.ts new file mode 100644 index 0000000000..af97c6d7a2 --- /dev/null +++ b/tests/formula-integration/vitest.config.ts @@ -0,0 +1,3 @@ +import createConfig from '@univerjs-infra/shared/vitest'; + +export default createConfig();