From 16907669a9610aaa94a4a8e38f038e6b9af4e134 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Mon, 4 Mar 2024 08:47:28 -0800 Subject: [PATCH] Configure unit test environment; add build & test CI (#104) Signed-off-by: Tyler Ohlsen --- .github/workflows/build-and-test.yml | 101 ++++++++++++++++++++++ babel.config.js | 16 ++++ opensearch_dashboards.json | 4 +- package.json | 1 + public/pages/workflows/workflows.test.tsx | 46 ++++++++++ test/index.ts | 6 ++ test/jest.config.js | 40 +++++++++ test/mocks/index.ts | 6 ++ test/mocks/mock_core_services.ts | 22 +++++ test/mocks/style_mock.ts | 6 ++ tsconfig.json | 1 + 11 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build-and-test.yml create mode 100644 babel.config.js create mode 100644 public/pages/workflows/workflows.test.tsx create mode 100644 test/index.ts create mode 100644 test/jest.config.js create mode 100644 test/mocks/index.ts create mode 100644 test/mocks/mock_core_services.ts create mode 100644 test/mocks/style_mock.ts diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..676df60f --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,101 @@ +name: Build & test +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" +env: + OPENSEARCH_DASHBOARDS_VERSION: 'main' + +jobs: + Get-CI-Image-Tag: + uses: opensearch-project/opensearch-build/.github/workflows/get-ci-image-tag.yml@main + with: + product: opensearch-dashboards + + build-and-test-linux: + needs: Get-CI-Image-Tag + name: Build & test + strategy: + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + container: + image: ${{ needs.Get-CI-Image-Tag.outputs.ci-image-version-linux }} + options: --user root + + steps: + - name: Checkout OpenSearch Dashboards + uses: actions/checkout@v2 + with: + repository: opensearch-project/OpenSearch-Dashboards + ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }} + path: OpenSearch-Dashboards + - name: Checkout plugin + uses: actions/checkout@v2 + with: + path: OpenSearch-Dashboards/plugins/dashboards-flow-framework + - name: Bootstrap / build / unit test the plugin + run: | + chown -R 1000:1000 `pwd` + cd ./OpenSearch-Dashboards/ + su `id -un 1000` -c "source $NVM_DIR/nvm.sh && nvm use && node -v && yarn -v && + cd ./plugins/dashboards-flow-framework && + whoami && yarn osd bootstrap && yarn build && yarn run test:jest --coverage" + - name: Uploads coverage + uses: codecov/codecov-action@v1 + + # TODO: once github actions supports windows and macos docker containers, we can + # merge these in to the above step's matrix, including adding windows support + build-and-test-windows-macos: + name: Build & test + strategy: + matrix: + os: [macos-latest] + runs-on: ${{ matrix.os }} + steps: + # Enable longer filenames for windows + - name: Enable longer filenames + if: ${{ matrix.os == 'windows-latest' }} + run: git config --system core.longpaths true + - name: Checkout OpenSearch Dashboards + uses: actions/checkout@v2 + with: + repository: opensearch-project/OpenSearch-Dashboards + ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }} + path: OpenSearch-Dashboards + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version-file: './OpenSearch-Dashboards/.nvmrc' + registry-url: 'https://registry.npmjs.org' + - name: Install Yarn + # Need to use bash to avoid having a windows/linux specific step + shell: bash + run: | + YARN_VERSION=$(node -p "require('./OpenSearch-Dashboards/package.json').engines.yarn") + echo "Installing yarn@$YARN_VERSION" + npm i -g yarn@$YARN_VERSION + - run: node -v + - run: yarn -v + - name: Checkout plugin + uses: actions/checkout@v2 + with: + path: OpenSearch-Dashboards/plugins/dashboards-flow-framework + - name: Bootstrap the plugin + run: | + cd OpenSearch-Dashboards/plugins/dashboards-flow-framework + yarn osd bootstrap + - name: Build the plugin + run: | + cd OpenSearch-Dashboards/plugins/dashboards-flow-framework + yarn build + - name: Run unit tests + run: | + cd OpenSearch-Dashboards/plugins/dashboards-flow-framework + yarn run test:jest --coverage + - name: Uploads coverage + uses: codecov/codecov-action@v1 + diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..12a3f644 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +module.exports = { + presets: [ + require('@babel/preset-env'), + require('@babel/preset-react'), + require('@babel/preset-typescript'), + ], + plugins: [ + ['@babel/plugin-transform-modules-commonjs', { allowTopLevelThis: true }], + [require('@babel/plugin-transform-runtime'), { regenerator: true }], + ], +}; diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index e2eb655f..746a629a 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -4,9 +4,7 @@ "opensearchDashboardsVersion": "3.0.0", "server": true, "ui": true, - "requiredBundles": [ - "opensearchDashboardsUtils" - ], + "requiredBundles": [], "requiredPlugins": [ "navigation" ], diff --git a/package.json b/package.json index f93c17e8..2b098fe8 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "opensearch": "../../scripts/use_node ../../scripts/opensearch", "lint:es": "../../scripts/use_node ../../scripts/eslint -c eslintrc.json", "lint:es:precommit": "yarn lint:es common/* public/* server/*", + "test:jest": "../../node_modules/.bin/jest --config ./test/jest.config.js", "build": "yarn plugin-helpers build && echo Renaming artifact to $npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip && mv ./build/$npm_package_config_plugin_name*.zip ./build/$npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip" }, "repository": { diff --git a/public/pages/workflows/workflows.test.tsx b/public/pages/workflows/workflows.test.tsx new file mode 100644 index 00000000..3c12244c --- /dev/null +++ b/public/pages/workflows/workflows.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-redux'; + +import { + BrowserRouter as Router, + RouteComponentProps, + Route, + Switch, +} from 'react-router-dom'; +import { store } from '../../store'; +import { Workflows } from './workflows'; + +jest.mock('../../services', () => { + const { mockCoreServices } = require('../../../test'); + return { + ...jest.requireActual('../../services'), + ...mockCoreServices, + }; +}); + +const renderWithRouter = () => ({ + ...render( + + + + } + /> + + + + ), +}); + +describe('Workflows', () => { + test('renders the page', () => { + const { getByText } = renderWithRouter(); + expect(getByText('Workflows')).not.toBeNull(); + }); +}); diff --git a/test/index.ts b/test/index.ts new file mode 100644 index 00000000..af422a51 --- /dev/null +++ b/test/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './mocks'; diff --git a/test/jest.config.js b/test/jest.config.js new file mode 100644 index 00000000..91b0e142 --- /dev/null +++ b/test/jest.config.js @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +module.exports = { + rootDir: '../', + roots: [''], + coverageDirectory: './coverage', + // we mock any style-related files and return an empty module. This is needed due to errors + // when jest tries to interpret these types of files. + moduleNameMapper: { + '\\.(css|less|scss|sass)$': '/test/mocks/style_mock.ts', + }, + testEnvironment: 'jest-environment-jsdom', + coverageReporters: ['lcov', 'text', 'cobertura'], + testMatch: ['**/*.test.js', '**/*.test.jsx', '**/*.test.ts', '**/*.test.tsx'], + collectCoverageFrom: [ + '**/*.ts', + '**/*.tsx', + '**/*.js', + '**/*.jsx', + '!**/models/**', + '!**/node_modules/**', + '!**/index.js', + '!/public/app.js', + '!/index.js', + '!/babel.config.js', + '!/test/**', + '!/server/**', + '!/coverage/**', + '!/scripts/**', + '!/build/**', + '!**/vendor/**', + ], + clearMocks: true, + modulePathIgnorePatterns: ['/offline-module-cache/'], + testPathIgnorePatterns: ['/build/', '/node_modules/'], + transformIgnorePatterns: ['/node_modules'], +}; diff --git a/test/mocks/index.ts b/test/mocks/index.ts new file mode 100644 index 00000000..bd15bcca --- /dev/null +++ b/test/mocks/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { mockCoreServices } from './mock_core_services'; diff --git a/test/mocks/mock_core_services.ts b/test/mocks/mock_core_services.ts new file mode 100644 index 00000000..40b86e08 --- /dev/null +++ b/test/mocks/mock_core_services.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const mockCoreServices = { + getCore: () => { + return { + chrome: { + setBreadcrumbs: jest.fn(), + }, + }; + }, + getNotifications: () => { + return { + toasts: { + addDanger: jest.fn().mockName('addDanger'), + addSuccess: jest.fn().mockName('addSuccess'), + }, + }; + }, +}; diff --git a/test/mocks/style_mock.ts b/test/mocks/style_mock.ts new file mode 100644 index 00000000..acbbabcc --- /dev/null +++ b/test/mocks/style_mock.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export default {}; diff --git a/tsconfig.json b/tsconfig.json index a598d0f4..688020fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -54,6 +54,7 @@ "public/**/*.ts", "public/**/*.tsx", "server/**/*.ts", + "test/**/*", "../../typings/**/*" ], "exclude": ["node_modules", "*/node_modules/"]