You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
portainer/test/e2e/cypress/support/commands.js

576 lines
17 KiB

import 'cypress-wait-until';
import _ from 'lodash-es';
let LOCAL_STORAGE_MEMORY = {};
let USER_TOKENS = [];
let ACTIVE_ENDPOINT_ID = '';
let ACTIVE_ENDPOINT_TYPE = '';
Cypress.Commands.add('saveLocalStorage', () => {
Object.keys(localStorage).forEach((key) => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add('restoreLocalStorage', () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
Cypress.Commands.add('saveUserToken', (username) => {
USER_TOKENS[username] = localStorage.getItem('portainer.JWT').slice(1, -1);
});
Cypress.Commands.add('deleteUserToken', (username) => {
delete USER_TOKENS[username];
});
Cypress.Commands.add('setBrowserToken', (username) => {
localStorage.setItem('portainer.JWT', USER_TOKENS[username]);
});
Cypress.Commands.add('clearBrowserToken', () => {
localStorage.removeItem('portainer.JWT');
});
Cypress.Commands.add('clearUserTokens', () => {
USER_TOKENS = [];
});
Cypress.Commands.add('initAdmin', (username, password) => {
cy.visit('/#/init/admin');
// Wait text, meaning page has loaded
cy.waitUntil(() => cy.contains('Please create the initial administrator user.'));
if (username != 'admin') {
cy.get('#username').clear().type(username);
}
cy.get('#password').type(password);
cy.get('#confirm_password').type(password);
cy.get('[type=submit]').click();
});
Cypress.Commands.add('initEndpoint', () => {
cy.get('[for=1]').click();
cy.get('[type=submit]').click();
});
Cypress.Commands.add('addNewEndpoint', (endpointName, endpointType, endpointURL) => {
const addEndpoint = (endpointName, endpointType, endpointURL) => {
cy.contains(endpointType).click();
cy.get('input[name=container_name]').type(endpointName);
cy.get('input[name=endpoint_url]').clear().type(endpointURL);
cy.get('span').contains('Add endpoint').click();
cy.waitUntil(() => cy.contains('Endpoints'));
};
cy.visit('/#!/endpoints/new');
cy.waitUntil(() => cy.contains('Create endpoint'));
addEndpoint(endpointName, endpointType, endpointURL);
});
Cypress.Commands.add('selectEndpoint', (endpointName) => {
cy.visit('/#!/home');
cy.waitUntil(() => cy.contains(endpointName).click());
cy.waitUntil(() => cy.get('rd-header-title[title-text="Dashboard"]'));
// Get info from active endpoint for building URL's
cy.request({
method: 'GET',
url: '/api/endpoints?limit=10&start=1',
auth: {
bearer: USER_TOKENS['admin'],
},
})
.its('body')
.then((body) => {
let endpointOBJ = _.find(body, { Name: endpointName });
ACTIVE_ENDPOINT_ID = endpointOBJ.Id;
ACTIVE_ENDPOINT_TYPE = endpointOBJ.Type;
});
});
Cypress.Commands.add('auth', (location, username, password) => {
if (location == 'frontend') {
cy.visit('/#/auth');
cy.get('#username').click();
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.waitUntil(() => cy.get('ng-transclude > .ng-scope:nth-child(1)')).click();
// Wait until you hit the home screen and get at least 1 endpoint item
cy.waitUntil(() => cy.get('endpoint-item')).saveUserToken(username);
} else {
cy.request({
method: 'POST',
url: '/api/auth',
body: {
username: username,
password: password,
},
})
.its('body')
.then((body) => {
USER_TOKENS[username] = body.jwt;
});
}
});
Cypress.Commands.add('createUser', (location, username, password) => {
// Setup team route to wait for response
cy.route2({ method: 'POST', path: '**/users' }).as('users');
if (location == 'frontend') {
cy.visit('/#!/users');
cy.waitUntil(() => cy.get('#username')).click();
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('#confirm_password').type(password);
cy.get('.btn-primary').click();
cy.wait('@users');
} else {
cy.request({
method: 'POST',
url: '/api/users',
failOnStatusCode: false,
auth: {
bearer: USER_TOKENS['admin'],
},
body: {
username: username,
password: password,
role: 2,
},
});
}
});
Cypress.Commands.add('deleteUser', (username) => {
cy.request({
method: 'GET',
url: '/api/users',
auth: {
bearer: USER_TOKENS['admin'],
},
})
.its('body')
.then((response) => {
let users = response;
for (var key in users) {
if (users[key].Username == username) {
cy.request({
method: 'DELETE',
url: '/api/users/' + users[key].Id,
auth: {
bearer: USER_TOKENS['admin'],
},
});
}
}
});
});
Cypress.Commands.add('deleteUsers', () => {
cy.request({
method: 'GET',
url: '/api/users',
auth: {
bearer: USER_TOKENS['admin'],
},
})
.its('body')
.then((response) => {
let users = response;
for (var key in users) {
if (users[key].Id != 1) {
cy.request({
method: 'DELETE',
url: '/api/users/' + users[key].Id,
auth: {
bearer: USER_TOKENS['admin'],
},
});
}
}
});
});
Cypress.Commands.add('createTeam', (location, teamName) => {
if (location == 'frontend') {
// Setup team route to wait for response
cy.route2('POST', '**/teams').as('teams');
cy.visit('/#!/teams');
cy.get('#team_name').click().type(teamName);
cy.get('.btn-primary').click();
cy.wait('@teams');
} else {
cy.request({
method: 'POST',
url: '/api/teams',
failOnStatusCode: false,
auth: {
bearer: USER_TOKENS['admin'],
},
body: {
Name: teamName,
},
});
}
});
Cypress.Commands.add('deleteTeam', (teamName) => {
cy.request({
method: 'GET',
url: '/api/teams',
auth: {
bearer: USER_TOKENS['admin'],
},
})
.its('body')
.then((response) => {
let teams = response;
for (var key in teams) {
if (teams[key].Name == teamName) {
cy.request({
method: 'DELETE',
url: '/api/teams/' + teams[key].Id,
auth: {
bearer: USER_TOKENS['admin'],
},
});
}
}
});
});
Cypress.Commands.add('deleteTeams', () => {
cy.request({
method: 'GET',
url: '/api/teams',
auth: {
bearer: USER_TOKENS['admin'],
},
})
.its('body')
.then((response) => {
let teams = response;
for (var key in teams) {
cy.request({
method: 'DELETE',
url: '/api/teams/' + teams[key].Id,
auth: {
bearer: USER_TOKENS['admin'],
},
});
}
});
});
// Navigate to teams view and assign a user to a team
Cypress.Commands.add('assignToTeam', (username, teamName) => {
cy.visit('/#!/teams');
// Click team to browse to related team details view
cy.clickLink(teamName);
// Get users table and execute within
cy.waitUntil(() => cy.contains('.widget', 'Users')).within(() => {
cy.contains('td', ' ' + username + ' ')
.children('span')
.click();
});
});
// Navigate to the endpoints view and give the user/team access
Cypress.Commands.add('assignAccess', (endpointName, entityName, entityType, role) => {
cy.visit('/#!/endpoints');
cy.contains('tr', endpointName).within(() => {
cy.clickLink('Manage access');
});
// Click user/team dropdown
cy.waitUntil(() => cy.get('.multiSelect > .ng-binding')).click();
// Assign based on entity type
var type;
if (entityType == 'team') {
type = 'fa-users';
} else {
type = 'fa-user';
}
cy.get('.' + type)
.parent()
.contains(entityName)
.click();
cy.get('.multiSelect > .ng-binding').click();
// If a role is provided, click role dropdown and select role
if (role) {
cy.get('.form-control:nth-child(1)').select(role);
}
// Click Create access button
cy.get('button[type=submit]').click();
});
Cypress.Commands.add('createStack', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/stacks/newstack`);
cy.waitUntil(() => cy.get('#stack_name'))
.click()
.type(resourceName);
if (ACTIVE_ENDPOINT_TYPE == '1') {
cy.get('.CodeMirror-scroll')
.click({ force: true })
.type("version: '2'")
.type('{enter}')
.type('services:')
.type('{enter}')
.type(' test:')
.type('{enter}')
.type(' image: nginx');
} else {
cy.get('.CodeMirror-scroll')
.click({ force: true })
.type("version: '3'")
.type('{enter}')
.type('services:')
.type('{enter}')
.type(' test:')
.type('{enter}')
.type(' image: nginx');
}
cy.contains('Deploy the stack').click();
// Wait for redirection to stacks view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Stacks list', { timeout: 60000 }));
}
});
Cypress.Commands.add('deleteStack', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/stacks`);
cy.waitUntil(() => cy.contains('Stacks list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.get('.modal-dialog').within(() => {
cy.get('button[class="btn btn-danger bootbox-accept"]').click();
});
cy.waitUntil(() => cy.contains('Stack successfully removed'));
} else {
cy.log('Delete stack via API');
}
});
Cypress.Commands.add('createService', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/services/new`);
cy.waitUntil(() => cy.get('#service_name'))
.click()
.type(resourceName);
cy.get('input[name=image_name]').type('nginx:alpine');
cy.contains('Create the service').click();
// Wait for redirection to services view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Service list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteService', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/services`);
cy.waitUntil(() => cy.contains('Service list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.get('.modal-dialog').within(() => {
cy.get('button[class="btn btn-danger bootbox-accept"]').click();
});
cy.waitUntil(() => cy.contains('Service successfully removed'));
} else {
cy.log('Delete service via API');
}
});
Cypress.Commands.add('createContainer', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/containers/new`);
cy.waitUntil(() => cy.get('#container_name'))
.click()
.type(resourceName);
cy.get('input[name=image_name]').type('nginx:alpine');
cy.contains('Deploy the container').click();
// Wait for redirection to containers view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Container list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteContainer', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/containers`);
cy.waitUntil(() => cy.contains('Container list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.get('.modal-dialog').within(() => {
cy.get('button[class="btn btn-danger bootbox-accept"]').click();
});
cy.waitUntil(() => cy.contains('Container successfully removed'));
} else {
cy.log('Delete container via API');
}
});
Cypress.Commands.add('createNetwork', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/networks/new`);
cy.waitUntil(() => cy.get('#network_name'))
.click()
.type(resourceName);
cy.contains('Create the network').click();
// Wait for redirection to networks view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Network list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteNetwork', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/networks`);
cy.waitUntil(() => cy.contains('Network list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.waitUntil(() => cy.contains('Network successfully removed'));
} else {
}
});
Cypress.Commands.add('createVolume', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/volumes/new`);
cy.waitUntil(() => cy.get('#volume_name'))
.click()
.type(resourceName);
cy.contains('Create the volume').click();
// Wait for redirection to volumes view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Volume list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteVolume', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/volumes`);
cy.waitUntil(() => cy.contains('Volume list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.waitUntil(() => cy.contains('Volume successfully removed'));
} else {
}
});
Cypress.Commands.add('createConfig', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/configs/new`);
cy.waitUntil(() => cy.get('#config_name'))
.click()
.type(resourceName);
cy.waitUntil(() => cy.get('.CodeMirror-scroll'))
.click()
.type('This is a config');
cy.get('button').contains('Create config').click();
// Wait for redirection to configs view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Configs list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteConfig', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/configs`);
cy.waitUntil(() => cy.contains('Configs list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.waitUntil(() => cy.contains('Config successfully removed'));
} else {
}
});
Cypress.Commands.add('createSecret', (location, resourceName, waitForRedirection = true) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/secrets/new`);
cy.waitUntil(() => cy.get('#secret_name'))
.click()
.type(resourceName);
cy.waitUntil(() => cy.get('textarea'))
.click()
.type('This is a secret');
cy.contains('Create the secret').click();
// Wait for redirection to secrets view
if (waitForRedirection) cy.waitUntil(() => cy.contains('Secrets list', { timeout: 120000 }));
}
});
Cypress.Commands.add('deleteSecret', (location, resourceName) => {
if (location == 'frontend') {
cy.visit(`/#!/${ACTIVE_ENDPOINT_ID}/docker/secrets`);
cy.waitUntil(() => cy.contains('Secrets list', { timeout: 120000 })).showAllResources();
cy.contains(new RegExp('^' + resourceName + '$', 'g'))
.closest('tr')
.within(() => {
cy.get('input[type=checkbox]').click();
});
cy.contains('Remove').click();
cy.waitUntil(() => cy.contains('Secret successfully removed'));
} else {
}
});
Cypress.Commands.add('modifyResource', (location, action, resourceType, resourceName) => {
// Dynamically call a custom cypress method on a resource of type 'resourceType'
cy[action + resourceType](location, resourceName);
});
// Method for modifying all resources in an endpoint with the default names
Cypress.Commands.add('modifyResources', (location, action) => {
const associatedResources = {
'1': ['Stack', 'Container', 'Network', 'Volume'],
'2': ['Stack', 'Service', 'Container', 'Network', 'Volume', 'Config', 'Secret'],
'3': ['Application'],
};
for (var res in associatedResources[ACTIVE_ENDPOINT_TYPE]) {
let resource = associatedResources[ACTIVE_ENDPOINT_TYPE][res];
cy.modifyResource(location, action, resource, resource.toLowerCase());
}
});
Cypress.Commands.add('clickLink', () => {
cy.waitUntil(() => cy.contains('a', label)).click();
});
Cypress.Commands.add('showAllResources', () => {
cy.waitUntil(() => cy.contains('.limitSelector', 'Items per page')).within(() => {
cy.get('select').select('All');
});
});