mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 14:09:31 +02:00
add e2e tests
This commit is contained in:
889
package-lock.json
generated
889
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@
|
|||||||
"@types/omggif": "^1.0.5",
|
"@types/omggif": "^1.0.5",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
|
"jimp": "^0.22.12",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"morsee": "^1.0.9",
|
"morsee": "^1.0.9",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import React, { ChangeEvent, useRef, useState } from 'react';
|
import React, { ChangeEvent, useRef, useState } from 'react';
|
||||||
import { Box, Stack, TextField } from '@mui/material';
|
import { Box, Stack, TextField, TextFieldProps } from '@mui/material';
|
||||||
import PaletteIcon from '@mui/icons-material/Palette';
|
import PaletteIcon from '@mui/icons-material/Palette';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
@@ -7,14 +7,15 @@ import { globalDescriptionFontSize } from '../../config/uiConfig';
|
|||||||
|
|
||||||
interface ColorSelectorProps {
|
interface ColorSelectorProps {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (val: string) => void;
|
onColorChange: (val: string) => void;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColorSelector: React.FC<ColorSelectorProps> = ({
|
const ColorSelector: React.FC<ColorSelectorProps & TextFieldProps> = ({
|
||||||
value = '#ffffff',
|
value = '#ffffff',
|
||||||
onChange,
|
onColorChange,
|
||||||
description
|
description,
|
||||||
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const [color, setColor] = useState<string>(value);
|
const [color, setColor] = useState<string>(value);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
@@ -22,7 +23,7 @@ const ColorSelector: React.FC<ColorSelectorProps> = ({
|
|||||||
const handleColorChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleColorChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const val = event.target.value;
|
const val = event.target.value;
|
||||||
setColor(val);
|
setColor(val);
|
||||||
onChange(val);
|
onColorChange(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -32,6 +33,7 @@ const ColorSelector: React.FC<ColorSelectorProps> = ({
|
|||||||
sx={{ backgroundColor: 'white' }}
|
sx={{ backgroundColor: 'white' }}
|
||||||
value={color}
|
value={color}
|
||||||
onChange={handleColorChange}
|
onChange={handleColorChange}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
<IconButton onClick={() => inputRef.current?.click()}>
|
<IconButton onClick={() => inputRef.current?.click()}>
|
||||||
<PaletteIcon />
|
<PaletteIcon />
|
||||||
|
@@ -125,12 +125,12 @@ export default function ChangeColorsInPng() {
|
|||||||
<Box>
|
<Box>
|
||||||
<ColorSelector
|
<ColorSelector
|
||||||
value={values.fromColor}
|
value={values.fromColor}
|
||||||
onChange={(val) => updateField('fromColor', val)}
|
onColorChange={(val) => updateField('fromColor', val)}
|
||||||
description={'Replace this color (from color)'}
|
description={'Replace this color (from color)'}
|
||||||
/>
|
/>
|
||||||
<ColorSelector
|
<ColorSelector
|
||||||
value={values.toColor}
|
value={values.toColor}
|
||||||
onChange={(val) => updateField('toColor', val)}
|
onColorChange={(val) => updateField('toColor', val)}
|
||||||
description={'With this color (to color)'}
|
description={'With this color (to color)'}
|
||||||
/>
|
/>
|
||||||
<TextFieldWithDesc
|
<TextFieldWithDesc
|
||||||
|
@@ -0,0 +1,72 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
import { Buffer } from 'buffer';
|
||||||
|
import path from 'path';
|
||||||
|
import Jimp from 'jimp';
|
||||||
|
|
||||||
|
test.describe('Convert JPG to PNG tool', () => {
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.goto('/png/convert-jgp-to-png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should convert jpg to png', async ({ page }) => {
|
||||||
|
// Upload image
|
||||||
|
const fileInput = page.locator('input[type="file"]');
|
||||||
|
const imagePath = path.join(__dirname, 'test.jpg');
|
||||||
|
await fileInput?.setInputFiles(imagePath);
|
||||||
|
|
||||||
|
// Click on download
|
||||||
|
const downloadPromise = page.waitForEvent('download');
|
||||||
|
await page.getByText('Save as').click();
|
||||||
|
|
||||||
|
// Intercept and read downloaded PNG
|
||||||
|
const download = await downloadPromise;
|
||||||
|
const downloadStream = await download.createReadStream();
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of downloadStream) {
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
const fileContent = Buffer.concat(chunks);
|
||||||
|
|
||||||
|
expect(fileContent.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Check that the first pixel is 0x808080ff
|
||||||
|
const image = await Jimp.read(fileContent);
|
||||||
|
const color = image.getPixelColor(0, 0);
|
||||||
|
expect(color).toBe(0x808080ff);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should apply transparency before converting jpg to png', async ({
|
||||||
|
page
|
||||||
|
}) => {
|
||||||
|
// Upload image
|
||||||
|
const fileInput = page.locator('input[type="file"]');
|
||||||
|
const imagePath = path.join(__dirname, 'test.jpg');
|
||||||
|
await fileInput?.setInputFiles(imagePath);
|
||||||
|
|
||||||
|
// Enable transparency on color 0x808080
|
||||||
|
await page.getByLabel('Enable PNG Transparency').check();
|
||||||
|
await page.getByTestId('color-input').fill('#808080');
|
||||||
|
|
||||||
|
// Click on download
|
||||||
|
const downloadPromise = page.waitForEvent('download');
|
||||||
|
await page.getByText('Save as').click();
|
||||||
|
|
||||||
|
// Intercept and read downloaded PNG
|
||||||
|
const download = await downloadPromise;
|
||||||
|
const downloadStream = await download.createReadStream();
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of downloadStream) {
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
const fileContent = Buffer.concat(chunks);
|
||||||
|
|
||||||
|
expect(fileContent.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Check that the first pixel is transparent
|
||||||
|
const image = await Jimp.read(fileContent);
|
||||||
|
const color = image.getPixelColor(0, 0);
|
||||||
|
expect(color).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
@@ -133,20 +133,21 @@ export default function ConvertJgpToPng() {
|
|||||||
compute={compute}
|
compute={compute}
|
||||||
getGroups={({ values, updateField }) => [
|
getGroups={({ values, updateField }) => [
|
||||||
{
|
{
|
||||||
title: 'From color and to color',
|
title: 'PNG Transparency Color',
|
||||||
component: (
|
component: (
|
||||||
<Box>
|
<Box>
|
||||||
<CheckboxWithDesc
|
<CheckboxWithDesc
|
||||||
key="enableTransparency"
|
key="enableTransparency"
|
||||||
title="PNG Transparency Color"
|
title="Enable PNG Transparency"
|
||||||
checked={!!values.enableTransparency}
|
checked={!!values.enableTransparency}
|
||||||
onChange={(value) => updateField('enableTransparency', value)}
|
onChange={(value) => updateField('enableTransparency', value)}
|
||||||
description="Make the color below transparent."
|
description="Make the color below transparent."
|
||||||
/>
|
/>
|
||||||
<ColorSelector
|
<ColorSelector
|
||||||
value={values.color}
|
value={values.color}
|
||||||
onChange={(val) => updateField('color', val)}
|
onColorChange={(val) => updateField('color', val)}
|
||||||
description={'With this color (to color)'}
|
description={'With this color (to color)'}
|
||||||
|
inputProps={{ 'data-testid': 'color-input' }}
|
||||||
/>
|
/>
|
||||||
<TextFieldWithDesc
|
<TextFieldWithDesc
|
||||||
value={values.similarity}
|
value={values.similarity}
|
||||||
|
BIN
src/pages/image/png/convert-jgp-to-png/test.jpg
Normal file
BIN
src/pages/image/png/convert-jgp-to-png/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@@ -118,7 +118,7 @@ export default function ChangeColorsInPng() {
|
|||||||
<Box>
|
<Box>
|
||||||
<ColorSelector
|
<ColorSelector
|
||||||
value={values.fromColor}
|
value={values.fromColor}
|
||||||
onChange={(val) => updateField('fromColor', val)}
|
onColorChange={(val) => updateField('fromColor', val)}
|
||||||
description={'Replace this color (from color)'}
|
description={'Replace this color (from color)'}
|
||||||
/>
|
/>
|
||||||
<TextFieldWithDesc
|
<TextFieldWithDesc
|
||||||
|
Reference in New Issue
Block a user