Skip to content

Commit

Permalink
Cypress init (#277)
Browse files Browse the repository at this point in the history
* feat: cypress implementation

* test change

* step through to creating management cluster

* add new data fields to ui components

* update: make cypress create management cluster test configurable/ wait for provision without fail.

* fix: do not destructure props to controlled text field. rendered field does not update accordingly without it.

* chore: add optional sub domain field

---------

Co-authored-by: CristhianF7 <CristhianF7@gmail.com>
Co-authored-by: Jared Edwards <jared@kubefirst.com>
  • Loading branch information
3 people authored Sep 19, 2023
1 parent f4829a6 commit 2fce747
Show file tree
Hide file tree
Showing 26 changed files with 1,595 additions and 743 deletions.
20 changes: 19 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,22 @@ POSTHOG_KEY=phc_1i5RDnv8Byf9w05fV8l02GSltpDwF9iyf0ry0U0Fw4r
MONGODB_USERNAME=k1
MONGODB_PASSWORD=k1
# Make sure the K1_ACCESS_TOKEN value matches the env var in the api
K1_ACCESS_TOKEN=feedkray
K1_ACCESS_TOKEN=feedkray
NEXT_PUBLIC_NODE_ENV=development
ENTERPRISE_API_URL=http://localhost:8080
CONSOLE_BASE_URL=http://localhost:3000
GITLAB_USER=
GITLAB_TOKEN=
GITHUB_USER=
GITHUB_TOKEN=
GITHUB_OWNER=
GITLAB_OWNER=
CIVO_TOKEN=
CIVO_CLOUD_REGION=
DNS_PROVIDER=
DOMAIN_NAME=
ALERTS_EMAIL=
CLOUDFLARE_TOKEN=
CLOUDFLARE_ORIGIN_CA_KEY=
CLUSTER_NAME=
SUB_DOMAIN=
2 changes: 1 addition & 1 deletion components/cloudProviderCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const CloudProviderCard: FunctionComponent<CloudProviderCardProps> = ({
const { logoSrc, label, description, learnMoreLink, height, width, beta } =
PROVIDER_OPTIONS[option] || {};
return (
<CardContainer {...rest} withHoverEffect={withHoverEffect}>
<CardContainer {...rest} withHoverEffect={withHoverEffect} data-test-id={`${option}-button`}>
<Image src={logoSrc} alt="logo" width={width} height={height} />
<DetailsContainer>
<LabelContainer>
Expand Down
2 changes: 1 addition & 1 deletion components/clusterReady/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const ClusterReady: FunctionComponent<ClusterRunningMessageProps> = ({
</Button>
</CopyToClipboard>
</PasswordContainer>
<Button variant="contained" color="primary">
<Button variant="contained" color="primary" data-test-id="launch-console">
<Link
href={`https://kubefirst.${domainName}/services`}
target="_blank"
Expand Down
6 changes: 2 additions & 4 deletions components/controlledFields/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { Control, Controller, FieldValues, UseControllerProps } from 'react-hook-form';

import TextFieldWithRef from '../textField/index';
Expand All @@ -16,8 +16,6 @@ function ControlledTextField<T extends FieldValues>({
disabled,
label,
required,
helperText,
onErrorText,
...props
}: ControlledTextFieldProps<T>) {
const [isBlur, setIsBlur] = useState(false);
Expand All @@ -38,7 +36,7 @@ function ControlledTextField<T extends FieldValues>({
required={required}
label={label}
error={isBlur && error !== undefined}
helperText={helperText || (isBlur && error !== undefined) ? onErrorText : undefined}
helperText={error && isBlur ? props.onErrorText : props.helperText}
/>
)}
/>
Expand Down
31 changes: 31 additions & 0 deletions components/controlledFields/textField/textField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { useForm } from 'react-hook-form';

import ControlledTextField from '../TextField';

const meta: Meta<typeof ControlledTextField> = {
component: ControlledTextField,
};

export default meta;

const ControlledTextFieldWithHooks = () => {
const { control, watch } = useForm({ defaultValues: { text: 'test' } });

const watchValue = watch('text');

return (
<ControlledTextField
control={control}
rules={{ required: false }}
label="Test"
name="text"
helperText={watchValue}
/>
);
};

export const Default: StoryObj<typeof ControlledTextField> = {
render: () => <ControlledTextFieldWithHooks />,
};
2 changes: 1 addition & 1 deletion components/gitProviderButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const GitProviderButton: FunctionComponent<GitProviderButtonProps> = ({
}) => {
const { logoSrc, label, height, width } = PROVIDER_OPTIONS[option];
return (
<Button {...rest} type={type}>
<Button {...rest} type={type} data-test-id={`${option}-button`}>
<Image src={logoSrc} alt="logo" width={width} height={height} />
<Typography variant="subtitle2">{label}</Typography>
</Button>
Expand Down
8 changes: 7 additions & 1 deletion components/installationButtons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ const InstallationButtons: FunctionComponent<InstallationButtonsProps> = ({
}) => (
<Container {...rest}>
{showBackButton && (
<Button variant="outlined" color="secondary" onClick={onBackButtonClick}>
<Button
variant="outlined"
color="secondary"
onClick={onBackButtonClick}
data-test-id="back-button"
>
Back
</Button>
)}
Expand All @@ -37,6 +42,7 @@ const InstallationButtons: FunctionComponent<InstallationButtonsProps> = ({
color="primary"
id="next"
disabled={nextButtonDisabled || isLoading}
data-test-id="next-button"
>
{isLoading && <CircularProgress size={20} sx={{ mr: '8px' }} />}
{nextButtonText}
Expand Down
1 change: 1 addition & 0 deletions components/textField/textField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const Default: Story = {
args: {
label: 'Default',
fullWidth: true,
helperText: 'test',
},
};

Expand Down
2 changes: 1 addition & 1 deletion containers/clusterForms/shared/authForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ const AuthForm: FunctionComponent = () => {
onChange={handleOnChangeToken}
onErrorText="Invalid token."
/>
<GitUserField>
<GitUserField data-test-id="gitUser">
<Typography
variant="labelLarge"
sx={{ display: 'flex', gap: '4px' }}
Expand Down
17 changes: 16 additions & 1 deletion containers/clusterForms/shared/setupForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@ const SetupForm: FunctionComponent = () => {
control,
setValue,
formState: { errors },
watch,
} = useFormContext<InstallValues>();

const [domainName, subDomain] = watch(['domainName', 'subDomain']);

const subDomainHelperText = !subDomain ? '' : `${subDomain}.${domainName}`;

const { cloudDomains, cloudRegions, installationStep, installType, values } = useAppSelector(
({ api, installation }) => ({
cloudDomains: api.cloudDomains,
Expand Down Expand Up @@ -154,7 +159,6 @@ const SetupForm: FunctionComponent = () => {
control={control}
name="cloudflareOriginCaIssuerKey"
label="Cloudflare origin ca issuer key"
required
rules={{
required: false,
}}
Expand All @@ -171,6 +175,17 @@ const SetupForm: FunctionComponent = () => {
rules={{ required: true }}
options={cloudDomains && formatDomains(cloudDomains)}
/>
<ControlledTextField
control={control}
name="subDomain"
label="Subdomain name"
defaultValue={values?.subDomain}
rules={{
maxLength: 25,
}}
onErrorText={errors.subDomain?.message}
helperText={subDomainHelperText}
/>
<ControlledTextField
control={control}
name="clusterName"
Expand Down
1 change: 1 addition & 0 deletions containers/clusterManagement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ const ClusterManagement: FunctionComponent = () => {
variant="contained"
style={{ marginRight: '24px' }}
onClick={handleAddWorkloadCluster}
test-data-id="add-workload-cluster"
>
Add workload cluster
</Button>
Expand Down
2 changes: 1 addition & 1 deletion containers/installationsSelection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const InstallationsSelection: FunctionComponent = () => {
))}
</ButtonContainer>
{gitProvider && (
<AdventureContent>
<AdventureContent data-test-id="cloud-section">
<Subtitle variant="subtitle2">Now select your cloud adventure</Subtitle>
<CloudProviderContainer>
{INSTALLATION_TYPES.filter((type) => ![InstallationType.LOCAL].includes(type)).map(
Expand Down
2 changes: 1 addition & 1 deletion containers/provision/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ const Provision: FunctionComponent = () => {

return (
<FormProvider {...methods}>
<Form component="form" onSubmit={handleSubmit(onSubmit)}>
<Form component="form" onSubmit={handleSubmit(onSubmit)} data-test-id="form-section">
<InstallationStepContainer
activeStep={installationStep}
steps={stepTitles}
Expand Down
8 changes: 8 additions & 0 deletions custom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,11 @@ declare module '@mui/material/Button' {
text: true;
}
}

declare global {
namespace Cypress {
interface Chainable {
openConsole(): Chainable<void>;
}
}
}
29 changes: 29 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineConfig } from 'cypress';
import * as dotenv from 'dotenv';
dotenv.config();

export default defineConfig({
env: {
CONSOLE_BASE_URL: process.env.CONSOLE_BASE_URL,
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
GITLAB_TOKEN: process.env.GITLAB_TOKEN,
GITHUB_USER: process.env.GITHUB_USER,
GITLAB_USER: process.env.GITLAB_USER,
GITLAB_OWNER: process.env.GITLAB_OWNER,
GITHUB_OWNER: process.env.GITHUB_OWNER,
CIVO_TOKEN: process.env.CIVO_TOKEN,
CIVO_CLOUD_REGION: process.env.CIVO_CLOUD_REGION,
DNS_PROVIDER: process.env.DNS_PROVIDER,
DOMAIN_NAME: process.env.DOMAIN_NAME,
ALERTS_EMAIL: process.env.ALERTS_EMAIL,
CLOUDFLARE_TOKEN: process.env.CLOUDFLARE_TOKEN,
CLOUDFLARE_ORIGIN_CA_KEY: process.env.CLOUDFLARE_ORIGIN_CA_KEY,
CLUSTER_NAME: process.env.CLUSTER_NAME,
SUB_DOMAIN: process.env.SUB_DOMAIN,
},
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
18 changes: 18 additions & 0 deletions cypress/e2e/1-create-cluster/add-workload-cluster.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
describe('add a workload cluster', () => {
beforeEach(() => {
cy.openConsole();
});

it('authentication', () => {
cy.get('[data-test-id="add-workload-cluster"]').click();

cy.get('.Mui-checked > .PrivateSwitchBase-input').click();
cy.get('.Mui-focused > .MuiInputBase-input').click();
cy.get('.sc-8ad53ea0-0:nth-child(2) .MuiInputBase-input').type('development');
cy.get('.Mui-focused > .MuiInputBase-input').click();
cy.get('.sc-8ad53ea0-0:nth-child(3) .MuiInputBase-input').type('development');
cy.get('#\3Ar1\3A').click();
cy.get('.Mui-disabled').click();
cy.get('.sc-1d58281b-2').submit();
});
});
87 changes: 87 additions & 0 deletions cypress/e2e/1-create-cluster/authentication.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const GITLAB_TOKEN = Cypress.env('GITLAB_TOKEN');
const GITLAB_USER = Cypress.env('GITLAB_USER');
const GITLAB_OWNER = Cypress.env('GITLAB_OWNER');
const CIVO_TOKEN = Cypress.env('CIVO_TOKEN');
const CIVO_CLOUD_REGION = Cypress.env('CIVO_CLOUD_REGION');
const DNS_PROVIDER = Cypress.env('DNS_PROVIDER');
const DOMAIN_NAME = Cypress.env('DOMAIN_NAME');
const ALERTS_EMAIL = Cypress.env('ALERTS_EMAIL');
const CLOUDFLARE_TOKEN = Cypress.env('CLOUDFLARE_TOKEN');
const CLOUDFLARE_ORIGIN_CA_KEY = Cypress.env('CLOUDFLARE_ORIGIN_CA_KEY');
const CLUSTER_NAME = Cypress.env('CLUSTER_NAME');
const SUB_DOMAIN = Cypress.env('SUB_DOMAIN');

describe('create cluster - setup', () => {
beforeEach(() => {
cy.openConsole();
});

it('authentication', () => {
cy.get('[data-test-id="gitlab-button"]').click();
cy.get('[data-test-id="cloud-section"]').contains('Now select your cloud adventure');
cy.get('[data-test-id="civo-button"]').click();
cy.get('[data-test-id="next-button"]').click();

cy.get('[data-test-id="form-section"]').contains('Now, let’s get you authenticated');
cy.get("[name='gitToken']").type(GITLAB_TOKEN);

cy.get('[data-test-id="gitUser"]').contains(GITLAB_USER);
cy.get("[name='gitOwner']").click();
// grab popper element and select option that contains GITLAB_OWNER
cy.get('.MuiAutocomplete-popper').then((popper) => {
cy.wrap(popper).contains(GITLAB_OWNER).click();
});

cy.get("[name='civo_auth.token']").type(CIVO_TOKEN);

cy.get('[data-test-id="next-button"]').click();
cy.get("[name='alertsEmail']").type(ALERTS_EMAIL);
cy.get("[name='cloudRegion']").click(); // click cloudRegion multiselect to open menu
cy.get('.MuiAutocomplete-popper').then((popper) => {
cy.wrap(popper).contains(CIVO_CLOUD_REGION).click();
});

cy.get("[name='dnsProvider']").click(); // click dnsProvider multiselect to open menu
cy.get('.MuiAutocomplete-popper').then((popper) => {
cy.wrap(popper).contains(DNS_PROVIDER).click();
});

cy.get("[name='cloudflareToken']").type(CLOUDFLARE_TOKEN);
cy.get("[name='cloudflareOriginCaIssuerKey']").type(CLOUDFLARE_ORIGIN_CA_KEY);

cy.get("[name='domainName']").click(); // click domainName multiselect to open menu
cy.get('.MuiAutocomplete-popper').then((popper) => {
cy.wrap(popper).contains(DOMAIN_NAME).click();
});

if (SUB_DOMAIN) {
cy.get("[name='subDomain']").type(SUB_DOMAIN);
}

cy.get("[name='clusterName']").type(CLUSTER_NAME);

cy.get("[name='advancedOptions']").click(); // click advanced options button

cy.get("[name='gitopsTemplateBranch']").type('civo-gitlab-workload-clusters');
cy.get('[data-test-id="next-button"]').click(); // create management cluster
// proceed to cluster provision completion page

cy.wait(2000); // give some time to make sure disabled prop is applied to next button

// recursive function to check for enabled next button when provisioning management cluster
function waitForEnabledButton() {
cy.get('[data-test-id="next-button"]').then((element) => {
if (!element.prop('disabled')) {
cy.wrap(element).click();
} else {
cy.wait(10000);
waitForEnabledButton();
}
});
}

waitForEnabledButton();

cy.get('[data-test-id="launch-console"]').click();
});
});
Loading

0 comments on commit 2fce747

Please sign in to comment.