test: add coverage for new features

This commit is contained in:
Nicolas Meienberger 2023-06-07 22:12:49 +02:00 committed by Nicolas Meienberger
parent 25ad967ccb
commit 70b6c20b29
10 changed files with 81 additions and 12 deletions

View file

@ -104,7 +104,7 @@ jobs:
cd runtipi cd runtipi
echo 'Checking out branch ${{ github.head_ref }}' echo 'Checking out branch ${{ github.head_ref }}'
git checkout ${{ github.head_ref }} git checkout ${{ github.head_ref }}
sudo ./scripts/start-e2e.sh latest sudo ./scripts/start-e2e.sh e2e
echo 'App deployed' echo 'App deployed'
host: ${{ steps.get-droplet-ip.outputs.droplet_ip }} host: ${{ steps.get-droplet-ip.outputs.droplet_ip }}
user: root user: root

View file

@ -30,8 +30,8 @@ test('user can install and uninstall app', async ({ page, context }) => {
await expect(page.getByText('Running')).toBeVisible({ timeout: 60000 }); await expect(page.getByText('Running')).toBeVisible({ timeout: 60000 });
await expect(page.getByText('App installed successfully')).toBeVisible(); await expect(page.getByText('App installed successfully')).toBeVisible();
await page.getByTestId('app-details').getByRole('button', { name: 'Open' }).click(); await page.getByTestId('app-details').getByRole('button', { name: 'Open' }).press('ArrowDown');
const [newPage] = await Promise.all([context.waitForEvent('page'), await page.getByRole('menuitem', { name: 'localhost:8000' }).click()]); const [newPage] = await Promise.all([context.waitForEvent('page'), await page.getByRole('menuitem', { name: `${process.env.SERVER_IP}:8000` }).click()]);
await newPage.waitForLoadState(); await newPage.waitForLoadState();
await expect(newPage.getByText('Hello World')).toBeVisible(); await expect(newPage.getByText('Hello World')).toBeVisible();

View file

@ -114,9 +114,11 @@ function generateTLSCert() {
if ! openssl req -x509 -newkey rsa:4096 -keyout traefik/tls/key.pem -out traefik/tls/cert.pem -days 365 -subj "/O=runtipi.io/OU=IT/CN=*.${domain}/emailAddress=webmaster@${domain}" -addext "subjectAltName = DNS:*.${domain},DNS:${domain}" -nodes; then if ! openssl req -x509 -newkey rsa:4096 -keyout traefik/tls/key.pem -out traefik/tls/cert.pem -days 365 -subj "/O=runtipi.io/OU=IT/CN=*.${domain}/emailAddress=webmaster@${domain}" -addext "subjectAltName = DNS:*.${domain},DNS:${domain}" -nodes; then
echo "Failed to generate TLS certificate" echo "Failed to generate TLS certificate"
else
echo "TLS certificate generated"
# Create a file to indicate that the certificate has been generated for this domain
touch "traefik/tls/$domain.txt"
fi fi
# Create a file to indicate that the certificate has been generated for this domain
touch "traefik/tls/$domain.txt"
} }

View file

@ -103,7 +103,7 @@ env_variables_json=$(cat <<EOF
"local_domain": "tipi.lan", "local_domain": "tipi.lan",
"repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")", "repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")",
"apps_repository": "${apps_repository}", "apps_repository": "${apps_repository}",
"domain": "tipi.lan", "domain": "example.com",
"storage_path": "${ROOT_FOLDER}", "storage_path": "${ROOT_FOLDER}",
"demo_mode": false, "demo_mode": false,
} }

View file

@ -253,7 +253,8 @@
"submit": "Save", "submit": "Save",
"user-settings-title": "User settings", "user-settings-title": "User settings",
"language": "Language", "language": "Language",
"help-translate": "Help translate Tipi" "help-translate": "Help translate Tipi",
"download-certificate": "Download certificate"
}, },
"security": { "security": {
"tab-title": "Security", "tab-title": "Security",

View file

@ -29,7 +29,7 @@ export const handlers = [
getTRPCMock({ getTRPCMock({
path: ['system', 'getSettings'], path: ['system', 'getSettings'],
type: 'query', type: 'query',
response: { internalIp: 'localhost', dnsIp: '1.1.1.1', appsRepoUrl: 'https://test.com/test', domain: 'tipi.localhost' }, response: { internalIp: 'localhost', dnsIp: '1.1.1.1', appsRepoUrl: 'https://test.com/test', domain: 'tipi.localhost', localDomain: 'tipi.lan' },
}), }),
getTRPCMock({ getTRPCMock({
path: ['system', 'updateSettings'], path: ['system', 'updateSettings'],

View file

@ -124,6 +124,54 @@ describe('Test: AppDetailsContainer', () => {
}); });
spy.mockRestore(); spy.mockRestore();
}); });
it('should open with domain when domain is clicked', async () => {
// Arrange
const app = createAppEntity({ overrides: { domain: 'test.com', exposed: true } });
const spy = jest.spyOn(window, 'open').mockImplementation(() => null);
render(<AppDetailsContainer app={app} />);
// Act
const openButton = screen.getByRole('button', { name: 'Open' });
userEvent.type(openButton, '{arrowdown}');
await waitFor(() => {
expect(screen.getByText(/test.com/)).toBeInTheDocument();
});
const openButtonItem = screen.getByText(/test.com/);
userEvent.click(openButtonItem);
// Assert
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(`https://test.com`, '_blank', 'noreferrer');
});
spy.mockRestore();
});
it('should open with local domain when local domain is clicked', async () => {
// Arrange
const app = createAppEntity({});
const spy = jest.spyOn(window, 'open').mockImplementation(() => null);
render(<AppDetailsContainer app={app} />);
// Act
const openButton = screen.getByRole('button', { name: 'Open' });
userEvent.type(openButton, '{arrowdown}');
await waitFor(() => {
expect(screen.getByText(/.tipi.lan/)).toBeInTheDocument();
});
const openButtonItem = screen.getByText(/.tipi.lan/);
userEvent.click(openButtonItem);
// Assert
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(`https://${app.id}.tipi.lan`, '_blank', 'noreferrer');
});
spy.mockRestore();
});
}); });
describe('Test: Install app', () => { describe('Test: Install app', () => {

View file

@ -39,6 +39,7 @@ describe('Test: SettingsForm', () => {
internalIp: 'invalid internal ip', internalIp: 'invalid internal ip',
appsRepoUrl: 'invalid url', appsRepoUrl: 'invalid url',
storagePath: 'invalid path', storagePath: 'invalid path',
localDomain: 'invalid local domain',
}; };
render(<SettingsForm onSubmit={jest.fn()} submitErrors={submitErrors} />); render(<SettingsForm onSubmit={jest.fn()} submitErrors={submitErrors} />);
@ -50,6 +51,7 @@ describe('Test: SettingsForm', () => {
expect(screen.getByText(submitErrors.internalIp)).toBeInTheDocument(); expect(screen.getByText(submitErrors.internalIp)).toBeInTheDocument();
expect(screen.getByText(submitErrors.appsRepoUrl)).toBeInTheDocument(); expect(screen.getByText(submitErrors.appsRepoUrl)).toBeInTheDocument();
expect(screen.getByText(submitErrors.storagePath)).toBeInTheDocument(); expect(screen.getByText(submitErrors.storagePath)).toBeInTheDocument();
expect(screen.getByText(submitErrors.localDomain)).toBeInTheDocument();
}); });
it('should correctly validate the form', async () => { it('should correctly validate the form', async () => {
@ -60,19 +62,21 @@ describe('Test: SettingsForm', () => {
const domainInput = screen.getByRole('textbox', { name: 'domain' }); const domainInput = screen.getByRole('textbox', { name: 'domain' });
const internalIpInput = screen.getByRole('textbox', { name: 'internalIp' }); const internalIpInput = screen.getByRole('textbox', { name: 'internalIp' });
const appsRepoUrlInput = screen.getByRole('textbox', { name: 'appsRepoUrl' }); const appsRepoUrlInput = screen.getByRole('textbox', { name: 'appsRepoUrl' });
const localDomainInput = screen.getByRole('textbox', { name: 'localDomain' });
// act // act
fireEvent.change(dnsIpInput, { target: { value: 'invalid ip' } }); fireEvent.change(dnsIpInput, { target: { value: 'invalid ip' } });
fireEvent.change(domainInput, { target: { value: 'invalid domain' } }); fireEvent.change(domainInput, { target: { value: 'invalid domain' } });
fireEvent.change(internalIpInput, { target: { value: 'invalid internal ip' } }); fireEvent.change(internalIpInput, { target: { value: 'invalid internal ip' } });
fireEvent.change(appsRepoUrlInput, { target: { value: 'invalid url' } }); fireEvent.change(appsRepoUrlInput, { target: { value: 'invalid url' } });
fireEvent.change(localDomainInput, { target: { value: 'invalid local domain' } });
fireEvent.click(submitButton); fireEvent.click(submitButton);
// assert // assert
await waitFor(() => { await waitFor(() => {
expect(screen.getAllByText('Invalid IP address')).toHaveLength(2); expect(screen.getAllByText('Invalid IP address')).toHaveLength(2);
}); });
expect(screen.getByText('Invalid domain')).toBeInTheDocument(); expect(screen.getAllByText('Invalid domain')).toHaveLength(2);
expect(screen.getByText('Invalid URL')).toBeInTheDocument(); expect(screen.getByText('Invalid URL')).toBeInTheDocument();
}); });
@ -90,4 +94,19 @@ describe('Test: SettingsForm', () => {
expect(onSubmit).toHaveBeenCalledTimes(1); expect(onSubmit).toHaveBeenCalledTimes(1);
}); });
}); });
it('should download the certificate when the download button is clicked', async () => {
// arrange
const spy = jest.spyOn(window, 'open').mockImplementation();
render(<SettingsForm onSubmit={jest.fn} />);
const downloadButton = screen.getByRole('button', { name: 'Download certificate' });
// act
fireEvent.click(downloadButton);
// assert
await waitFor(() => {
expect(spy).toHaveBeenCalledTimes(1);
});
});
}); });

View file

@ -183,9 +183,8 @@ export const SettingsForm = (props: IProps) => {
error={errors.localDomain?.message} error={errors.localDomain?.message}
placeholder="tipi.lan" placeholder="tipi.lan"
/> />
<Button className="mt-2" onClick={downloadCertificate}> <Button className="mt-2" onClick={downloadCertificate}>
Download certificate {t('download-certificate')}
</Button> </Button>
</div> </div>
<Button loading={loading} type="submit" className="btn-success"> <Button loading={loading} type="submit" className="btn-success">

View file

@ -65,7 +65,7 @@ nextApp.prepare().then(async () => {
EventDispatcher.clear(); EventDispatcher.clear();
// Run database migrations // Run database migrations
if (getConfig().NODE_ENV === 'development') { if (getConfig().NODE_ENV !== 'development') {
await runPostgresMigrations(); await runPostgresMigrations();
} }
setConfig('status', 'RUNNING'); setConfig('status', 'RUNNING');