mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 14:09:31 +02:00
test: init
This commit is contained in:
46
.github/workflows/ci.yml
vendored
Normal file
46
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main # or the branch you want to trigger the workflow on
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18' # Specify the Node.js version you want to use
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
|
||||
- name: Deploy to Netlify
|
||||
uses: nwtgck/actions-netlify@v1.2
|
||||
with:
|
||||
publish-dir: ./build
|
||||
production-branch: main
|
||||
deploy-message: Deploy from GitHub Actions
|
||||
enable-pull-request-comment: true
|
||||
enable-commit-comment: true
|
||||
overwrites-pull-request-comment: true
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
timeout-minutes: 1
|
||||
|
@@ -20,7 +20,8 @@
|
||||
"test:ui": "vitest --ui",
|
||||
"lint": "eslint src --max-warnings=0",
|
||||
"typecheck": "tsc --project tsconfig.json --noEmit",
|
||||
"prepare": "husky install"
|
||||
"prepare": "husky install",
|
||||
"prebuild": "npm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.4",
|
||||
|
@@ -1,32 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
|
||||
import App from './App'
|
||||
|
||||
describe('<App />', () => {
|
||||
it('should render the App', () => {
|
||||
const { container } = render(<App />)
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', {
|
||||
name: /Welcome!/i,
|
||||
level: 1
|
||||
})
|
||||
).toBeInTheDocument()
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
/This is a boilerplate build with Vite, React 18, TypeScript, Vitest, Testing Library, TailwindCSS 3, Eslint and Prettier./i
|
||||
)
|
||||
).toBeInTheDocument()
|
||||
|
||||
expect(
|
||||
screen.getByRole('link', {
|
||||
name: /start building for free/i
|
||||
})
|
||||
).toBeInTheDocument()
|
||||
|
||||
expect(screen.getByRole('img')).toBeInTheDocument()
|
||||
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
@@ -1,4 +1,4 @@
|
||||
export {default as useDebounce} from "./useDebounce";
|
||||
export {default as useTimeout} from "./useTimeout";
|
||||
export {default as usePrevious} from "./usePrevious";
|
||||
export {default as useUpdateEffect} from "./useUpdateEffect";
|
||||
export { default as useDebounce } from './useDebounce';
|
||||
export { default as useTimeout } from './useTimeout';
|
||||
export { default as usePrevious } from './usePrevious';
|
||||
export { default as useUpdateEffect } from './useUpdateEffect';
|
||||
|
@@ -9,10 +9,9 @@ import ToolTextResult from '../../../components/result/ToolTextResult';
|
||||
import { Field, Formik, FormikProps, useFormikContext } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import ToolOptions from '../../../components/ToolOptions';
|
||||
import { splitIntoChunks, splitTextByLength } from './service';
|
||||
import { compute, SplitOperatorType } from './service';
|
||||
import { CustomSnackBarContext } from '../../../contexts/CustomSnackBarContext';
|
||||
|
||||
type SplitOperatorType = 'symbol' | 'regex' | 'length' | 'chunks';
|
||||
const initialValues = {
|
||||
splitSeparatorType: 'symbol' as SplitOperatorType,
|
||||
symbolValue: ' ',
|
||||
@@ -160,24 +159,20 @@ export default function SplitText() {
|
||||
regexValue,
|
||||
lengthValue
|
||||
} = values;
|
||||
let splitText;
|
||||
switch (splitSeparatorType) {
|
||||
case 'symbol':
|
||||
splitText = input.split(symbolValue);
|
||||
break;
|
||||
case 'regex':
|
||||
splitText = input.split(new RegExp(regexValue));
|
||||
break;
|
||||
case 'length':
|
||||
splitText = splitTextByLength(input, Number(lengthValue));
|
||||
break;
|
||||
case 'chunks':
|
||||
splitText = splitIntoChunks(input, Number(chunksValue)).map(
|
||||
(chunk) => `${charBeforeChunk}${chunk}${charAfterChunk}`
|
||||
);
|
||||
}
|
||||
const res = splitText.join(outputSeparator);
|
||||
setResult(res);
|
||||
|
||||
setResult(
|
||||
compute(
|
||||
splitSeparatorType,
|
||||
input,
|
||||
symbolValue,
|
||||
regexValue,
|
||||
Number(lengthValue),
|
||||
Number(chunksValue),
|
||||
charBeforeChunk,
|
||||
charAfterChunk,
|
||||
outputSeparator
|
||||
)
|
||||
);
|
||||
} catch (exception: unknown) {
|
||||
if (exception instanceof Error)
|
||||
showSnackBar(exception.message, 'error');
|
||||
|
@@ -1,4 +1,6 @@
|
||||
export function splitTextByLength(text: string, length: number) {
|
||||
export type SplitOperatorType = 'symbol' | 'regex' | 'length' | 'chunks';
|
||||
|
||||
function splitTextByLength(text: string, length: number) {
|
||||
if (length <= 0) throw new Error('Length must be a positive number');
|
||||
const result: string[] = [];
|
||||
for (let i = 0; i < text.length; i += length) {
|
||||
@@ -7,7 +9,7 @@ export function splitTextByLength(text: string, length: number) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function splitIntoChunks(text: string, numChunks: number) {
|
||||
function splitIntoChunks(text: string, numChunks: number) {
|
||||
if (numChunks <= 0)
|
||||
throw new Error('Number of chunks must be a positive number');
|
||||
const totalLength = text.length;
|
||||
@@ -31,3 +33,33 @@ export function splitIntoChunks(text: string, numChunks: number) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function compute(
|
||||
splitSeparatorType: SplitOperatorType,
|
||||
input: string,
|
||||
symbolValue: string,
|
||||
regexValue: string,
|
||||
lengthValue: number,
|
||||
chunksValue: number,
|
||||
charBeforeChunk: string,
|
||||
charAfterChunk: string,
|
||||
outputSeparator: string
|
||||
) {
|
||||
let splitText;
|
||||
switch (splitSeparatorType) {
|
||||
case 'symbol':
|
||||
splitText = input.split(symbolValue);
|
||||
break;
|
||||
case 'regex':
|
||||
splitText = input.split(new RegExp(regexValue));
|
||||
break;
|
||||
case 'length':
|
||||
splitText = splitTextByLength(input, lengthValue);
|
||||
break;
|
||||
case 'chunks':
|
||||
splitText = splitIntoChunks(input, chunksValue).map(
|
||||
(chunk) => `${charBeforeChunk}${chunk}${charAfterChunk}`
|
||||
);
|
||||
}
|
||||
return splitText.join(outputSeparator);
|
||||
}
|
||||
|
72
src/pages/string/split/string-split.test.ts
Normal file
72
src/pages/string/split/string-split.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { compute } from './service';
|
||||
|
||||
describe('compute function', () => {
|
||||
it('should split by symbol', () => {
|
||||
const result = compute('symbol', 'hello world', ' ', '', 0, 0, '', '', ',');
|
||||
expect(result).toBe('hello,world');
|
||||
});
|
||||
|
||||
it('should split by regex', () => {
|
||||
const result = compute(
|
||||
'regex',
|
||||
'hello1world2again',
|
||||
'',
|
||||
'\\d',
|
||||
0,
|
||||
0,
|
||||
'',
|
||||
'',
|
||||
','
|
||||
);
|
||||
expect(result).toBe('hello,world,again');
|
||||
});
|
||||
|
||||
it('should split by length', () => {
|
||||
const result = compute('length', 'helloworld', '', '', 3, 0, '', '', ',');
|
||||
expect(result).toBe('hel,low,orl,d');
|
||||
});
|
||||
|
||||
it('should split into chunks', () => {
|
||||
const result = compute(
|
||||
'chunks',
|
||||
'helloworldagain',
|
||||
'',
|
||||
'',
|
||||
0,
|
||||
3,
|
||||
'[',
|
||||
']',
|
||||
','
|
||||
);
|
||||
expect(result).toBe('[hello],[world],[again]');
|
||||
});
|
||||
|
||||
it('should handle empty input', () => {
|
||||
const result = compute('symbol', '', ' ', '', 0, 0, '', '', ',');
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle length greater than text length', () => {
|
||||
const result = compute('length', 'hi', '', '', 5, 0, '', '', ',');
|
||||
expect(result).toBe('hi');
|
||||
});
|
||||
|
||||
it('should handle chunks greater than text length', () => {
|
||||
expect(() => {
|
||||
compute('chunks', 'hi', '', '', 0, 5, '', '', ',');
|
||||
}).toThrow('Text length must be at least as long as the number of chunks');
|
||||
});
|
||||
|
||||
it('should handle invalid length', () => {
|
||||
expect(() => {
|
||||
compute('length', 'hello', '', '', -1, 0, '', '', ',');
|
||||
}).toThrow('Length must be a positive number');
|
||||
});
|
||||
|
||||
it('should handle invalid chunks', () => {
|
||||
expect(() => {
|
||||
compute('chunks', 'hello', '', '', 0, 0, '', '', ',');
|
||||
}).toThrow('Number of chunks must be a positive number');
|
||||
});
|
||||
});
|
@@ -1,7 +1,7 @@
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
// https://vitejs.dev/config https://vitest.dev/config
|
||||
export default defineConfig({
|
||||
@@ -10,6 +10,6 @@ export default defineConfig({
|
||||
globals: true,
|
||||
environment: 'happy-dom',
|
||||
setupFiles: '.vitest/setup',
|
||||
include: ['**/test.{ts,tsx}']
|
||||
include: ['**/*.test.{ts,tsx}']
|
||||
}
|
||||
})
|
||||
});
|
||||
|
Reference in New Issue
Block a user