mirror of https://github.com/portainer/portainer
576 lines
17 KiB
JavaScript
576 lines
17 KiB
JavaScript
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', (label) => {
|
|
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');
|
|
});
|
|
});
|