MM-T3180 Detox/E2E for LDAP login (#4863)
* E2E for LDAP login * add LDAP test and sync * update per comment * add api commands to ensure LDAP user has team * clean up * clean up file check * update per comment
This commit is contained in:
parent
11898abce2
commit
64882b3176
16 changed files with 382 additions and 134 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -89,6 +89,10 @@ ios/sentry.properties
|
|||
coverage
|
||||
.tmp
|
||||
|
||||
# E2E testing
|
||||
mattermost-license.txt
|
||||
*.mattermost-license
|
||||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
|
||||
|
|
|
|||
32
detox/e2e/support/fixtures/ldap_users.json
Normal file
32
detox/e2e/support/fixtures/ldap_users.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"dev-1": {
|
||||
"username": "dev.one",
|
||||
"password": "Password1",
|
||||
"email": "success+devone@simulator.amazonses.com",
|
||||
"userType": "Admin"
|
||||
},
|
||||
"dev-2": {
|
||||
"username": "dev.two",
|
||||
"password": "Password1",
|
||||
"email": "success+testtwo@simulator.amazonses.com",
|
||||
"userType": "Admin"
|
||||
},
|
||||
"test-1": {
|
||||
"username": "test.one",
|
||||
"password": "Password1",
|
||||
"email": "success+testone@simulator.amazonses.com",
|
||||
"userType": ""
|
||||
},
|
||||
"board-1": {
|
||||
"username": "board.one",
|
||||
"password": "Password1",
|
||||
"email": "success+boardone@simulator.amazonses.com",
|
||||
"userType": ""
|
||||
},
|
||||
"board-2": {
|
||||
"username": "board.two",
|
||||
"password": "Password1",
|
||||
"email": "success+boardtwo@simulator.amazonses.com",
|
||||
"userType": ""
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import FormData from 'form-data';
|
||||
import fs from 'fs';
|
||||
|
||||
import client from './client';
|
||||
|
||||
export const getResponseFromError = (err) => {
|
||||
const {response} = err;
|
||||
if (!response) {
|
||||
|
|
@ -19,3 +24,24 @@ If testing against a server other than the default local instance, you may set t
|
|||
|
||||
return {error: data, status};
|
||||
};
|
||||
|
||||
export const apiUploadFile = async (name, absFilePath, requestOptions = {}) => {
|
||||
if (!fs.existsSync(absFilePath)) {
|
||||
return {error: {message: `File upload error. "${name}" file does not exist at ${absFilePath}`}};
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append(name, fs.createReadStream(absFilePath));
|
||||
|
||||
try {
|
||||
const response = await client.request({
|
||||
...requestOptions,
|
||||
data: formData,
|
||||
headers: formData.getHeaders(),
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import Channel from './channel';
|
||||
import Ldap from './ldap';
|
||||
import Post from './post';
|
||||
import Setup from './setup';
|
||||
import System from './system';
|
||||
|
|
@ -10,6 +11,7 @@ import User from './user';
|
|||
|
||||
export {
|
||||
Channel,
|
||||
Ldap,
|
||||
Post,
|
||||
Setup,
|
||||
System,
|
||||
|
|
|
|||
68
detox/e2e/support/server_api/ldap.js
Normal file
68
detox/e2e/support/server_api/ldap.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import jestExpect from 'expect';
|
||||
|
||||
import client from './client';
|
||||
import {getResponseFromError} from './common';
|
||||
|
||||
// ****************************************************************
|
||||
// LDAP
|
||||
// See https://api.mattermost.com/#tag/LDAP
|
||||
//
|
||||
// Exported API function should have the following:
|
||||
// - documented using JSDoc
|
||||
// - meaningful description
|
||||
// - match the referenced API endpoints
|
||||
// - parameter/s defined by `@param`
|
||||
// - return value defined by `@return`
|
||||
// ****************************************************************
|
||||
|
||||
/**
|
||||
* Synchronize any user attribute changes in the configured AD/LDAP server with Mattermost.
|
||||
* See https://api.mattermost.com/#tag/LDAP/paths/~1ldap~1sync/post
|
||||
* @return {string} returns {status} on success or {error, status} on error
|
||||
*/
|
||||
export const apiLDAPSync = async () => {
|
||||
try {
|
||||
const response = await client.post('/api/v4/ldap/sync');
|
||||
|
||||
return response;
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test the current AD/LDAP configuration to see if the AD/LDAP server can be contacted successfully.
|
||||
* See https://api.mattermost.com/#tag/LDAP/paths/~1ldap~1test/post
|
||||
* @return {string} returns {status} on success or {error, status} on error
|
||||
*/
|
||||
export const apiLDAPTest = async () => {
|
||||
try {
|
||||
const response = await client.post('/api/v4/ldap/test');
|
||||
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that LDAP server can connect and is synchronized with Mattermost server.
|
||||
*/
|
||||
export const apiRequireLDAPServer = async () => {
|
||||
const {error: testError} = await apiLDAPTest();
|
||||
jestExpect(testError).toBeUndefined();
|
||||
|
||||
const {error: syncError} = await apiLDAPSync();
|
||||
jestExpect(syncError).toBeUndefined();
|
||||
};
|
||||
|
||||
export const Ldap = {
|
||||
apiLDAPSync,
|
||||
apiLDAPTest,
|
||||
apiRequireLDAPServer,
|
||||
};
|
||||
|
||||
export default Ldap;
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import merge from 'merge-deep';
|
||||
import merge from 'deepmerge';
|
||||
import jestExpect from 'expect';
|
||||
import path from 'path';
|
||||
|
||||
import testConfig from '@support/test_config';
|
||||
|
||||
import client from './client';
|
||||
import {getResponseFromError} from './common';
|
||||
import {apiUploadFile, getResponseFromError} from './common';
|
||||
import defaultServerConfig from './default_config.json';
|
||||
|
||||
// ****************************************************************
|
||||
|
|
@ -21,6 +23,8 @@ import defaultServerConfig from './default_config.json';
|
|||
// - return value defined by `@return`
|
||||
// ****************************************************************
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
/**
|
||||
* Check system health.
|
||||
* See https://api.mattermost.com/#tag/system/paths/~1system~1ping/get
|
||||
|
|
@ -57,7 +61,7 @@ export const apiGetConfig = async () => {
|
|||
export const apiUpdateConfig = async (newConfig = {}) => {
|
||||
try {
|
||||
const {config: currentConfig} = await apiGetConfig();
|
||||
const config = merge(currentConfig, getDefaultConfig(), newConfig);
|
||||
const config = merge.all([currentConfig, getDefaultConfig(), newConfig]);
|
||||
|
||||
const response = await client.put(
|
||||
'/api/v4/config',
|
||||
|
|
@ -70,18 +74,117 @@ export const apiUpdateConfig = async (newConfig = {}) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getDefaultConfig = () => {
|
||||
function getDefaultConfig() {
|
||||
const fromEnv = {
|
||||
LdapSettings: {
|
||||
LdapServer: testConfig.ldapServer,
|
||||
LdapPort: testConfig.ldapPort,
|
||||
},
|
||||
ServiceSettings: {SiteURL: testConfig.siteUrl},
|
||||
};
|
||||
|
||||
return merge(defaultServerConfig, fromEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client license.
|
||||
* See https://api.mattermost.com/#tag/system/paths/~1license~1client/get
|
||||
* @return {Object} returns {license} on success or {error, status} on error
|
||||
*/
|
||||
export const apiGetClientLicense = async () => {
|
||||
try {
|
||||
const response = await client.get('/api/v4/license/client?format=old');
|
||||
|
||||
return {license: response.data};
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Require server license to successfully continue.
|
||||
* @return {Object} returns {license} on success or fail when no license
|
||||
*/
|
||||
export const apiRequireLicense = async () => {
|
||||
const {license} = await getClientLicense();
|
||||
|
||||
if (license.IsLicensed !== 'true') {
|
||||
console.error('Server has no Enterprise license.');
|
||||
}
|
||||
jestExpect(license.IsLicensed).toEqual('true');
|
||||
|
||||
return {license};
|
||||
};
|
||||
|
||||
/**
|
||||
* Require server license with specific feature to successfully continue.
|
||||
* @param {string} key - feature, e.g. LDAP
|
||||
* @return {Object} returns {license} on success or fail when no license or no license to specific feature.
|
||||
*/
|
||||
export const apiRequireLicenseForFeature = async (key = '') => {
|
||||
const {license} = await getClientLicense();
|
||||
|
||||
if (license.IsLicensed !== 'true') {
|
||||
console.error('Server has no Enterprise license.');
|
||||
}
|
||||
jestExpect(license.IsLicensed).toEqual('true');
|
||||
|
||||
let hasLicenseKey = false;
|
||||
for (const [k, v] of Object.entries(license)) {
|
||||
if (k === key && v === 'true') {
|
||||
hasLicenseKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasLicenseKey) {
|
||||
console.error(`Server has no license for "${key}" feature.`);
|
||||
}
|
||||
jestExpect(hasLicenseKey).toEqual(true);
|
||||
|
||||
return {license};
|
||||
};
|
||||
|
||||
/**
|
||||
* Upload server license with file expected at "/detox/e2e/support/fixtures/mattermost-license.txt"
|
||||
*/
|
||||
export const apiUploadLicense = async () => {
|
||||
const absFilePath = path.resolve(__dirname, '../../support/fixtures/mattermost-license.txt');
|
||||
const response = await apiUploadFile('license', absFilePath, {url: '/api/v4/license', method: 'POST'});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get client license.
|
||||
* If no license, try to upload if license file is available at "/support/fixtures/mattermost-license.txt".
|
||||
*/
|
||||
async function getClientLicense() {
|
||||
const {license} = await apiGetClientLicense();
|
||||
if (license.IsLicensed === 'true') {
|
||||
return {license};
|
||||
}
|
||||
|
||||
// Upload a license if server is currently not loaded with license
|
||||
const response = await apiUploadLicense();
|
||||
if (response.error) {
|
||||
console.warn(response.error.message);
|
||||
return {license};
|
||||
}
|
||||
|
||||
// Get an updated client license
|
||||
const out = await apiGetClientLicense();
|
||||
return {license: out.license};
|
||||
}
|
||||
|
||||
export const System = {
|
||||
apiCheckSystemHealth,
|
||||
apiGetConfig,
|
||||
apiUpdateConfig,
|
||||
apiGetClientLicense,
|
||||
apiRequireLicense,
|
||||
apiRequireLicenseForFeature,
|
||||
apiUploadLicense,
|
||||
};
|
||||
|
||||
export default System;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,22 @@ export const apiAddUserToTeam = async (userId, teamId) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get team members for user.
|
||||
* See https://api.mattermost.com/#tag/teams/paths/~1users~1{user_id}~1teams~1members/get
|
||||
* @param {string} userId
|
||||
* @return {Object} returns {teams} on success or {error, status} on error
|
||||
*/
|
||||
export const apiGetTeamMembersForUser = async (userId = 'me') => {
|
||||
try {
|
||||
const response = await client.get(`/api/v4/users/${userId}/teams`);
|
||||
|
||||
return {teams: response.data};
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
function generateRandomTeam(type, prefix) {
|
||||
const randomId = getRandomId();
|
||||
|
||||
|
|
@ -72,6 +88,7 @@ function generateRandomTeam(type, prefix) {
|
|||
export const Team = {
|
||||
apiAddUserToTeam,
|
||||
apiCreateTeam,
|
||||
apiGetTeamMembersForUser,
|
||||
};
|
||||
|
||||
export default Team;
|
||||
|
|
|
|||
|
|
@ -111,6 +111,21 @@ export const apiGetUserById = async (userId) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a user by username.
|
||||
* See https://api.mattermost.com/#tag/users/paths/~1users~1username~1{username}/get
|
||||
* @param {string} username
|
||||
*/
|
||||
export const apiGetUserByUsername = async (username) => {
|
||||
try {
|
||||
const response = await client.get(`/api/v4/users/username/${username}`);
|
||||
|
||||
return {user: response.data};
|
||||
} catch (err) {
|
||||
return getResponseFromError(err);
|
||||
}
|
||||
};
|
||||
|
||||
function generateRandomUser(prefix) {
|
||||
const randomId = getRandomId();
|
||||
|
||||
|
|
@ -131,6 +146,7 @@ export const User = {
|
|||
apiCreateUser,
|
||||
apiGetMe,
|
||||
apiGetUserById,
|
||||
apiGetUserByUsername,
|
||||
};
|
||||
|
||||
export default User;
|
||||
|
|
|
|||
|
|
@ -6,4 +6,6 @@ module.exports = {
|
|||
siteUrl: process.env.SITE_URL || 'http://localhost:8065',
|
||||
adminUsername: process.env.ADMIN_USERNAME || 'sysadmin',
|
||||
adminPassword: process.env.ADMIN_PASSWORD || 'Sys@dmin-sample1',
|
||||
ldapServer: process.env.LDAP_SERVER || 'localhost',
|
||||
ldapPort: process.env.LDAP_PORT || 389,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ export async function fulfillLoginScreen(user = {}) {
|
|||
await element(by.id('username_input')).replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.id('login_screen')).tap({x: 10, y: 10});
|
||||
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.id('login_screen')).tap({x: 10, y: 10});
|
||||
|
||||
await element(by.id('signin_button')).tap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import nodeExpect from 'expect';
|
||||
import jestExpect from 'expect';
|
||||
|
||||
import {toChannelScreen} from '@support/ui/screen';
|
||||
import {Channel, Post, Setup} from '@support/server_api';
|
||||
|
|
@ -48,9 +48,9 @@ describe('Messaging', () => {
|
|||
// # Check that no duplicate message is saved.
|
||||
const {channel} = await Channel.apiGetChannelByName(team.name, 'town-square');
|
||||
const {posts} = await Post.apiGetPostsInChannel(channel.id);
|
||||
nodeExpect(posts.length).toEqual(3);
|
||||
nodeExpect(posts[0].message).toEqual(message);
|
||||
nodeExpect(posts[1].message).toEqual(`${user.username} joined the team.`);
|
||||
nodeExpect(posts[2].message).toEqual('sysadmin joined the team.');
|
||||
jestExpect(posts.length).toEqual(3);
|
||||
jestExpect(posts[0].message).toEqual(message);
|
||||
jestExpect(posts[1].message).toEqual(`${user.username} joined the team.`);
|
||||
jestExpect(posts[2].message).toEqual('sysadmin joined the team.');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,15 +7,17 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {Setup} from '@support/server_api';
|
||||
import {Setup, System} from '@support/server_api';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
import {fulfillSelectServerScreen} from '@support/ui/screen';
|
||||
import {isAndroid, timeouts, wait} from '@support/utils';
|
||||
|
||||
describe('On boarding', () => {
|
||||
let config;
|
||||
let user;
|
||||
|
||||
beforeAll(async () => {
|
||||
({config} = await System.apiGetConfig());
|
||||
({user} = await Setup.apiInit());
|
||||
});
|
||||
|
||||
|
|
@ -89,7 +91,7 @@ describe('On boarding', () => {
|
|||
await element(by.id('username_input')).typeText('any');
|
||||
|
||||
// Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
|
|
@ -103,7 +105,7 @@ describe('On boarding', () => {
|
|||
await element(by.id('password_input')).typeText('any');
|
||||
|
||||
// Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
|
|
@ -122,13 +124,13 @@ describe('On boarding', () => {
|
|||
await element(by.id('username_input')).replaceText('any');
|
||||
|
||||
// Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Enter invalid password
|
||||
await element(by.id('password_input')).replaceText('any');
|
||||
|
||||
// Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
|
|
@ -147,13 +149,13 @@ describe('On boarding', () => {
|
|||
await element(by.id('username_input')).replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Enter valid password
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// Tap "Sign in" button
|
||||
await element(by.id('signin_button')).tap();
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {Setup} from '@support/server_api';
|
||||
import {Setup, System} from '@support/server_api';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
|
||||
describe('Smoke Tests', () => {
|
||||
it('MM-T3179 Log in - Email / password', async () => {
|
||||
const {config} = await System.apiGetConfig();
|
||||
const {user} = await Setup.apiInit();
|
||||
|
||||
// * Verify that it starts with the Select Server screen
|
||||
|
|
@ -30,13 +31,13 @@ describe('Smoke Tests', () => {
|
|||
await element(by.id('username_input')).replaceText(user.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// # Type in password
|
||||
await element(by.id('password_input')).replaceText(user.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text('Mattermost')).tap();
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.text('Sign in')).tap();
|
||||
|
|
|
|||
71
detox/e2e/test/smoke_test/login_ldap.e2e.js
Normal file
71
detox/e2e/test/smoke_test/login_ldap.e2e.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Ldap, Setup, System, Team, User} from '@support/server_api';
|
||||
import {serverUrl} from '@support/test_config';
|
||||
import ldapUsers from '@support/fixtures/ldap_users.json';
|
||||
|
||||
describe('Smoke Tests', () => {
|
||||
const testOne = ldapUsers['test-1'];
|
||||
let config;
|
||||
|
||||
beforeAll(async () => {
|
||||
// * Verify that the server has license with LDAP feature
|
||||
await System.apiRequireLicenseForFeature('LDAP');
|
||||
|
||||
// # Enable LDAP
|
||||
({config} = await System.apiUpdateConfig({LdapSettings: {Enable: true}}));
|
||||
|
||||
// * Check that LDAP server can connect and is synchronized with Mattermost server
|
||||
await Ldap.apiRequireLDAPServer();
|
||||
|
||||
await ensureUserHasTeam(testOne);
|
||||
});
|
||||
|
||||
it('MM-T3180 Log in - LDAP', async () => {
|
||||
// * Verify that it starts with the Select Server screen
|
||||
await expect(element(by.id('select_server_screen'))).toBeVisible();
|
||||
|
||||
// # Type in the server URL
|
||||
await element(by.id('server_url_input')).replaceText(serverUrl);
|
||||
|
||||
// # Tap connect button
|
||||
await element(by.text('Connect')).tap();
|
||||
|
||||
// # Verify that it goes into Login screen
|
||||
await expect(element(by.id('login_screen'))).toBeVisible();
|
||||
|
||||
// # Type in username
|
||||
await element(by.id('username_input')).replaceText(testOne.username);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// # Type in password
|
||||
await element(by.id('password_input')).replaceText(testOne.password);
|
||||
|
||||
// # Tap anywhere to hide keyboard
|
||||
await element(by.text(config.TeamSettings.SiteName)).tap();
|
||||
|
||||
// # Tap "Sign in" button
|
||||
await element(by.text('Sign in')).tap();
|
||||
|
||||
// * Verify that the user has successfully logged in by checking it redirects into the Channel screen
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
async function ensureUserHasTeam(ldapUser) {
|
||||
// # Login as LDAP user to sync with the server
|
||||
await User.apiLogin(ldapUser);
|
||||
|
||||
// # Login as sysadmin and ensure LDAP user is member of at least one team
|
||||
await User.apiAdminLogin();
|
||||
const {user} = await User.apiGetUserByUsername(ldapUser.username);
|
||||
const {teams} = await Team.apiGetTeamMembersForUser(user.id);
|
||||
|
||||
if (!teams?.length) {
|
||||
const {team} = await Setup.apiInit();
|
||||
await Team.apiAddUserToTeam(user.id, team.id);
|
||||
}
|
||||
}
|
||||
127
detox/package-lock.json
generated
127
detox/package-lock.json
generated
|
|
@ -2319,30 +2319,6 @@
|
|||
"wrap-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"clone-deep": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz",
|
||||
"integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"for-own": "^0.1.3",
|
||||
"is-plain-object": "^2.0.1",
|
||||
"kind-of": "^3.0.2",
|
||||
"lazy-cache": "^1.0.3",
|
||||
"shallow-clone": "^0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
|
|
@ -3077,15 +3053,6 @@
|
|||
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
|
||||
"dev": true
|
||||
},
|
||||
"for-own": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
|
||||
"integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"for-in": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
|
|
@ -3093,13 +3060,13 @@
|
|||
"dev": true
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz",
|
||||
"integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
|
|
@ -5330,12 +5297,6 @@
|
|||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
|
||||
"dev": true
|
||||
},
|
||||
"leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
|
|
@ -5448,28 +5409,6 @@
|
|||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"merge-deep": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz",
|
||||
"integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arr-union": "^3.1.0",
|
||||
"clone-deep": "^0.2.4",
|
||||
"kind-of": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
|
@ -5543,24 +5482,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mixin-object": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz",
|
||||
"integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"for-in": "^0.1.3",
|
||||
"is-extendable": "^0.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"for-in": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz",
|
||||
"integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
|
|
@ -6289,6 +6210,17 @@
|
|||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
|
|
@ -6653,35 +6585,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"shallow-clone": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz",
|
||||
"integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "^0.1.1",
|
||||
"kind-of": "^2.0.1",
|
||||
"lazy-cache": "^0.2.3",
|
||||
"mixin-object": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz",
|
||||
"integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-buffer": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz",
|
||||
"integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@
|
|||
"axios": "0.20.0",
|
||||
"babel-jest": "26.3.0",
|
||||
"babel-plugin-module-resolver": "4.0.0",
|
||||
"deepmerge": "4.2.2",
|
||||
"detox": "17.4.4",
|
||||
"form-data": "3.0.0",
|
||||
"jest": "26.4.2",
|
||||
"jest-circus": "26.4.2",
|
||||
"jest-cli": "26.4.2",
|
||||
"merge-deep": "3.0.2",
|
||||
"uuid": "8.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue