diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..f2c549b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -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
+
diff --git a/package.json b/package.json
index a7c5979..21137f2 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/components/test.tsx b/src/components/test.tsx
deleted file mode 100644
index e1bbd3f..0000000
--- a/src/components/test.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { render, screen } from '@testing-library/react'
-
-import App from './App'
-
-describe('', () => {
- it('should render the App', () => {
- const { container } = render()
-
- 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()
- })
-})
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index cc9ab3f..1929925 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -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';
diff --git a/src/pages/string/split/index.tsx b/src/pages/string/split/index.tsx
index 9e11ded..e75d697 100644
--- a/src/pages/string/split/index.tsx
+++ b/src/pages/string/split/index.tsx
@@ -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');
diff --git a/src/pages/string/split/service.ts b/src/pages/string/split/service.ts
index 5775b79..cea1bdc 100644
--- a/src/pages/string/split/service.ts
+++ b/src/pages/string/split/service.ts
@@ -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);
+}
diff --git a/src/pages/string/split/string-split.test.ts b/src/pages/string/split/string-split.test.ts
new file mode 100644
index 0000000..4917cdc
--- /dev/null
+++ b/src/pages/string/split/string-split.test.ts
@@ -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');
+ });
+});
diff --git a/vite.config.ts b/vite.config.ts
index 38502f8..0597438 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,7 @@
///
-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}']
}
-})
+});