Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,13 @@ module.exports = defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'http://localhost:3000',
chromeWebSecurity: false, // Required for OIDC testing
setupNodeEvents(on, config) {
on("task", {
log(message) {
console.log(message);
return null;
}
})
}
},
});
119 changes: 74 additions & 45 deletions cypress/e2e/repo.cy.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,84 @@
describe('Repo', () => {
beforeEach(() => {
let repoName;
let cloneURL;
let csrfToken;
let cookies;
let repoId;

before(() => {
cy.login('admin', 'admin');

cy.visit('/dashboard/repo');
// Create a new repo
cy.getCSRFToken().then((csrfToken) => {
repoName = `${Date.now()}`;
cloneURL = `http://localhost:8000/github.com/cypress-test/${repoName}.git`;

cy.request({
method: 'POST',
url: 'http://localhost:8080/api/v1/repo',
body: {
project: 'cypress-test',
name: repoName,
url: `https://github.com/cypress-test/${repoName}.git`
},
headers: {
cookie: cookies?.join('; ') || '',
'X-CSRF-TOKEN': csrfToken
}
}).then((res) => {
expect(res.status).to.eq(200);
repoId = res.body._id;
});
});
});

// prevent failures on 404 request and uncaught promises
it('Opens tooltip with correct content and can copy', () => {
cy.visit('/dashboard/repo');
cy.on('uncaught:exception', () => false);

const tooltipQuery = 'div[role="tooltip"]';

// Check the tooltip isn't open to start with
cy.get(tooltipQuery)
.should('not.exist');

// Find the repo's Code button and click it
cy.get(`a[href="/dashboard/repo/${repoId}"]`)
.closest('tr')
.find('span')
.contains('Code')
.should('exist')
.click();

// Check tooltip is open and contains the correct clone URL
cy.get(tooltipQuery)
.should('exist')
.find('span')
.contains(cloneURL)
.should('exist')
.parent()
.find('span')
.next()
.get('svg.octicon-copy')
.should('exist')
.click()
.get('svg.octicon-copy')
.should('not.exist')
.get('svg.octicon-check')
.should('exist');
});

describe('Code button for repo row', () => {
it('Opens tooltip with correct content and can copy', () => {
const cloneURLRegex = /http:\/\/localhost:8000\/(?:[^\/]+\/).+\.git/;
const tooltipQuery = 'div[role="tooltip"]';

cy
// tooltip isn't open to start with
.get(tooltipQuery)
.should('not.exist');

cy
// find a table row for a repo (any will do)
.get('table#RepoListTable>tbody>tr')
// find the nearby span containing Code we can click to open the tooltip
.find('span')
.contains('Code')
.should('exist')
.click();

cy
// find the newly opened tooltip
.get(tooltipQuery)
.should('exist')
.find('span')
// check it contains the url we expect
.contains(cloneURLRegex)
.should('exist')
.parent()
// find the adjacent span that contains the svg
.find('span')
.next()
// check it has the copy icon first and click it
.get('svg.octicon-copy')
.should('exist')
.click()
// check the icon has changed to the check icon
.get('svg.octicon-copy')
.should('not.exist')
.get('svg.octicon-check')
.should('exist');

// failed to successfully check the clipboard
after(() => {
// Delete the repo
cy.getCSRFToken().then((csrfToken) => {
cy.request({
method: 'DELETE',
url: `http://localhost:8080/api/v1/repo/${repoName}/delete`,
headers: {
cookie: cookies?.join('; ') || '',
'X-CSRF-TOKEN': csrfToken
}
});
});
});
});
22 changes: 22 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,25 @@ Cypress.Commands.add('login', (username, password) => {
cy.url().should('include', '/dashboard/repo');
});
});

Cypress.Commands.add('getCSRFToken', () => {
return cy.request('GET', 'http://localhost:8080/api/v1/repo').then((res) => {
let cookies = res.headers['set-cookie'];

if (typeof cookies === 'string') {
cookies = [cookies];
}

if (!cookies) {
throw new Error('No cookies found in response');
}

const csrfCookie = cookies.find(c => c.startsWith('csrf='));
if (!csrfCookie) {
throw new Error('No CSRF cookie found in response headers');
}

const token = csrfCookie.split('=')[1].split(';')[0];
return cy.wrap(decodeURIComponent(token));
});
});
8 changes: 4 additions & 4 deletions src/ui/components/Tasks/Tasks.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';
import Checkbox from '@material-ui/core/Checkbox';
import Tooltip from '@material-ui/core/Tooltip';
Expand Down Expand Up @@ -30,7 +30,7 @@ export default function Tasks(props) {
setChecked(newChecked);
};
const { tasksIndexes, tasks, rtlActive } = props;
const tableCellClasses = classnames(classes.tableCell, {
const tableCellClasses = clsx(classes.tableCell, {
[classes.tableCellRTL]: rtlActive,
});
return (
Expand Down Expand Up @@ -60,7 +60,7 @@ export default function Tasks(props) {
classes={{ tooltip: classes.tooltip }}
>
<IconButton aria-label='Edit' className={classes.tableActionButton}>
<Edit className={classes.tableActionButtonIcon + ' ' + classes.edit} />
<Edit className={clsx(classes.tableActionButtonIcon, classes.edit)} />
</IconButton>
</Tooltip>
<Tooltip
Expand All @@ -70,7 +70,7 @@ export default function Tasks(props) {
classes={{ tooltip: classes.tooltip }}
>
<IconButton aria-label='Close' className={classes.tableActionButton}>
<Close className={classes.tableActionButtonIcon + ' ' + classes.close} />
<Close className={clsx(classes.tableActionButtonIcon, classes.close)} />
</IconButton>
</Tooltip>
</TableCell>
Expand Down
4 changes: 2 additions & 2 deletions src/ui/services/repo.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ const getRepos = async (
setIsLoading(true);
await axios(url.toString(), getAxiosConfig())
.then((response) => {
const data = response.data;
setData(data);
const sortedRepos = response.data.sort((a, b) => a.name.localeCompare(b.name));
setData(sortedRepos);
})
.catch((error) => {
setIsError(true);
Expand Down
2 changes: 1 addition & 1 deletion test/processors/blockForAuth.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe('blockForAuth', () => {
expect(result).to.equal(action);
}),
{
numRuns: 100
numRuns: 1000
}
);
});
Expand Down
2 changes: 1 addition & 1 deletion test/testCheckRepoInAuthList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('Check a Repo is in the authorised list', async () => {
const result = await processor.exec(null, action);
expect(result.error).to.be.true;
}),
{ numRuns: 100 },
{ numRuns: 1000 },
);
});
});
Expand Down
Loading