Detox/E2E: Migrate e2e javascript to typescript (#6059)

* Detox/E2E: Migrate to typescript

* Add jest.config.js

* Add moduleMapper to config.json

* Add cookie jar to axios client, fix tsconfig.json and default_config.json

* Take keyboard into consideration; clean test for now for this migration PR

* Revert changes on path_builder

* Attempt to fix dep issues

* Update detox dep

* Added missing @type dev dependencies

* Fix dep order

* Fix unit tests

* Added dynamic year to email.ts
This commit is contained in:
Joseph Baylon
2022-03-17 17:35:26 -07:00
committed by GitHub
parent 088aa193ab
commit 1d9c371bfb
55 changed files with 933 additions and 282 deletions

View File

@@ -11,6 +11,7 @@ type Props = {
borderColor?: string;
color?: string;
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
testID?: string;
type?: 'Normal' | 'Small';
/**
@@ -27,6 +28,7 @@ export default function Badge({
type = 'Normal',
value,
style,
testID,
...rest
}: Props) {
const [opacity] = React.useState(() => new Animated.Value(visible ? 1 : 0));
@@ -114,6 +116,7 @@ export default function Badge({
additionalStyle,
restStyle,
]}
testID={testID}
{...rest}
>
{badge}

View File

@@ -56,6 +56,7 @@ exports[`Server Icon Server Icon Component should match snapshot with mentions 1
"opacity": 1,
}
}
testID="server_icon"
>
<Icon
color="rgba(255,255,255,0.56)"
@@ -92,6 +93,7 @@ exports[`Server Icon Server Icon Component should match snapshot with mentions 1
],
}
}
testID="server_icon.badge"
>
1
</Text>
@@ -122,6 +124,7 @@ exports[`Server Icon Server Icon Component should match snapshot with unreads 1`
"opacity": 1,
}
}
testID="server_icon"
>
<Icon
color="rgba(255,255,255,0.56)"
@@ -158,6 +161,7 @@ exports[`Server Icon Server Icon Component should match snapshot with unreads 1`
],
}
}
testID="server_icon.badge"
>
</Text>

View File

@@ -21,6 +21,7 @@ type Props = {
onPress?: () => void;
size?: number;
style?: StyleProp<ViewStyle>;
testID?: string;
unreadStyle?: StyleProp<ViewStyle>;
}
@@ -46,6 +47,7 @@ export default function ServerIcon({
onPress,
size = 24,
style,
testID,
unreadStyle,
}: Props) {
const theme = useTheme();
@@ -61,6 +63,7 @@ export default function ServerIcon({
disabled={onPress === undefined}
onPress={onPress}
type='opacity'
testID={testID}
>
<CompassIcon
size={size}
@@ -73,6 +76,7 @@ export default function ServerIcon({
color={badgeColor}
visible={hasBadge}
style={memoizedStyle}
testID={`${testID}.badge`}
value={count}
/>
</TouchableWithFeedback>

View File

@@ -24,6 +24,7 @@ describe('Server Icon', () => {
<Icon
hasUnreads={true}
mentionCount={0}
testID='server_icon'
/>,
);
@@ -35,6 +36,7 @@ describe('Server Icon', () => {
<Icon
hasUnreads={false}
mentionCount={1}
testID='server_icon'
/>,
);

View File

@@ -12,9 +12,10 @@ import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
onPress?: (e: GestureResponderEvent) => void;
icon?: string;
testID?: string;
text?: string;
}
export default function BottomSheetButton({onPress, icon, text}: Props) {
export default function BottomSheetButton({onPress, icon, testID, text}: Props) {
const theme = useTheme();
const styles = getStyleSheet(theme);
@@ -23,6 +24,7 @@ export default function BottomSheetButton({onPress, icon, text}: Props) {
onPress={onPress}
type='opacity'
style={styles.button}
testID={testID}
>
{icon && (
<View style={styles.icon_container}>

View File

@@ -16,6 +16,7 @@ type Props = {
onPress?: (e: GestureResponderEvent) => void;
showButton: boolean;
showTitle: boolean;
testID?: string;
title?: string;
}
@@ -42,18 +43,27 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
};
});
const BottomSheetContent = ({buttonText, buttonIcon, children, onPress, showButton, showTitle, title}: Props) => {
const BottomSheetContent = ({buttonText, buttonIcon, children, onPress, showButton, showTitle, testID, title}: Props) => {
const dimensions = useWindowDimensions();
const theme = useTheme();
const isTablet = useIsTablet();
const styles = getStyleSheet(theme);
const separatorWidth = Math.max(dimensions.width, 450);
const buttonTestId = `${testID}.${buttonText?.replace(/ /g, '_').toLocaleLowerCase()}.button`;
return (
<View style={styles.container}>
<View
style={styles.container}
testID={`${testID}.screen`}
>
{showTitle &&
<View style={styles.titleContainer}>
<Text style={styles.titleText}>{title}</Text>
<Text
style={styles.titleText}
testID={`${testID}.title`}
>
{title}
</Text>
</View>
}
<>
@@ -65,6 +75,7 @@ const BottomSheetContent = ({buttonText, buttonIcon, children, onPress, showButt
<Button
onPress={onPress}
icon={buttonIcon}
testID={buttonTestId}
text={buttonText}
/>
<View style={{paddingBottom: Platform.select({ios: (isTablet ? 20 : 32), android: 20})}}/>

View File

@@ -153,6 +153,7 @@ export default function Servers() {
mentionCount={total.mentions}
onPress={onPress}
style={styles.icon}
testID={'channel_list.servers.server_icon'}
/>
);
}

View File

@@ -58,6 +58,7 @@ const ServerList = ({servers}: Props) => {
onPress={onAddServer}
showButton={true}
showTitle={!isTablet}
testID='server_list'
title={intl.formatMessage({id: 'your.servers', defaultMessage: 'Your servers'})}
>
<View style={styles.container}>

View File

@@ -45,6 +45,9 @@ const ServerOptions = ({onEdit, onLogin, onLogout, onRemove, progress, server}:
defaultMessage: 'Log in',
});
const serverItem = `server_list.server_item.${server.displayName.replace(/ /g, '_').toLocaleLowerCase()}`;
const loginOrLogoutOptionTestId = isLoggedIn ? `${serverItem}.logout.option` : `${serverItem}.login.option`;
return (
<View style={styles.container}>
<Option
@@ -54,6 +57,7 @@ const ServerOptions = ({onEdit, onLogin, onLogout, onRemove, progress, server}:
positionX={OPTION_SIZE * 3}
progress={progress}
style={styles.left}
testID={`${serverItem}.edit.option`}
text={intl.formatMessage({id: 'servers.edit', defaultMessage: 'Edit'})}
/>
<Option
@@ -62,6 +66,7 @@ const ServerOptions = ({onEdit, onLogin, onLogout, onRemove, progress, server}:
onPress={onRemove}
positionX={OPTION_SIZE * 2}
progress={progress}
testID={`${serverItem}.remove.option`}
text={intl.formatMessage({id: 'servers.remove', defaultMessage: 'Remove'})}
/>
<Option
@@ -71,6 +76,7 @@ const ServerOptions = ({onEdit, onLogin, onLogout, onRemove, progress, server}:
positionX={OPTION_SIZE}
progress={progress}
style={styles.right}
testID={loginOrLogoutOptionTestId}
text={sessionText}
/>
</View>

View File

@@ -17,6 +17,7 @@ type Props = {
positionX: number;
progress: Animated.AnimatedInterpolation;
style?: StyleProp<ViewStyle>;
testID?: string;
text: string;
}
@@ -37,7 +38,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
},
}));
const ServerOption = ({color, icon, onPress, positionX, progress, style, text}: Props) => {
const ServerOption = ({color, icon, onPress, positionX, progress, style, testID, text}: Props) => {
const theme = useTheme();
const styles = getStyleSheet(theme);
const containerStyle = useMemo(() => {
@@ -52,7 +53,10 @@ const ServerOption = ({color, icon, onPress, positionX, progress, style, text}:
return (
<Animated.View style={{transform: [{translateX: trans}]}}>
<View style={containerStyle}>
<View
style={containerStyle}
testID={testID}
>
<RectButton
style={centeredStyle}
onPress={onPress}

View File

@@ -290,6 +290,9 @@ const ServerItem = ({highlight, isActive, server, tutorialWatched}: Props) => {
return () => clearTimeout(time);
}, [highlight, tutorialWatched]);
const serverItem = `server_list.server_item.${server.displayName.replace(/ /g, '_').toLocaleLowerCase()}`;
const serverItemTestId = isActive ? `${serverItem}.active` : `${serverItem}.inactive`;
return (
<>
<Swipeable
@@ -304,6 +307,7 @@ const ServerItem = ({highlight, isActive, server, tutorialWatched}: Props) => {
<View
style={containerStyle}
ref={viewRef}
testID={serverItemTestId}
>
<RectButton
onPress={onServerPressed}
@@ -323,6 +327,7 @@ const ServerItem = ({highlight, isActive, server, tutorialWatched}: Props) => {
size={36}
unreadStyle={styles.unread}
style={styles.serverIcon}
testID={`${serverItem}}.server_icon`}
/>
}
{switching &&

View File

@@ -1,6 +1,6 @@
{
"testRunner": "jest --forceExit --detectOpenHandles",
"runnerConfig": "e2e/config.js",
"runnerConfig": "e2e/config.json",
"configurations": {
"ios.sim.debug": {
"binaryPath": "../ios/Build/Products/Debug-iphonesimulator/Mattermost.app",

View File

@@ -1,28 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
const platform = process.env.IOS ? 'ios' : 'android';
module.exports = {
setupFilesAfterEnv: ['./init.js'],
testEnvironment: './environment',
testRunner: 'jest-circus/runner',
testTimeout: 120000,
testRegex: '\\.e2e\\.js$',
reporters: [
'../node_modules/detox/runners/jest/streamlineReporter',
['jest-junit', {
suiteName: 'Mobile App E2E with Detox and Jest',
outputDirectory: './artifacts',
outputName: `${platform}-junit.xml`,
uniqueOutputName: false,
}],
['jest-html-reporters', {
pageTitle: 'Mobile App E2E with Detox and Jest',
publicPath: './artifacts',
filename: `${platform}-report.html`,
expand: false,
}],
],
verbose: true,
};

16
detox/e2e/config.json Normal file
View File

@@ -0,0 +1,16 @@
{
"setupFilesAfterEnv": ["./test/setup.ts"],
"maxWorkers": 1,
"testEnvironment": "./environment",
"testRunner": "jest-circus/runner",
"testTimeout": 120000,
"testRegex": "\\.e2e\\.ts$",
"transform": {
"\\.ts?$": "ts-jest"
},
"reporters": ["detox/runners/jest/streamlineReporter"],
"verbose": true,
"moduleNameMapper": {
"^@support/(.*)": "<rootDir>/support/$1"
}
}

View File

@@ -26,7 +26,7 @@ import {getResponseFromError} from './common';
* @param {Object} option.bot - bot object to be created
* @return {Object} returns {bot} on success or {error, status} on error
*/
export const apiCreateBot = async (baseUrl, {prefix = 'bot', bot = null} = {}) => {
export const apiCreateBot = async (baseUrl: string, {prefix = 'bot', bot = null}: any = {}): Promise<any> => {
try {
const newBot = bot || generateRandomBot({prefix});

View File

@@ -26,7 +26,7 @@ import {getResponseFromError} from './common';
* @param {string} channelId - The channel ID
* @return {Object} returns {member} on success or {error, status} on error
*/
export const apiAddUserToChannel = async (baseUrl, userId, channelId) => {
export const apiAddUserToChannel = async (baseUrl: string, userId: string, channelId: string): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/channels/${channelId}/members`,
@@ -49,7 +49,7 @@ export const apiAddUserToChannel = async (baseUrl, userId, channelId) => {
* @param {Object} option.channel - channel object to be created
* @return {Object} returns {channel} on success or {error, status} on error
*/
export const apiCreateChannel = async (baseUrl, {teamId = null, type = 'O', prefix = 'channel', channel = null} = {}) => {
export const apiCreateChannel = async (baseUrl: string, {teamId = null, type = 'O', prefix = 'channel', channel = null}: any = {}): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/channels`,
@@ -69,7 +69,7 @@ export const apiCreateChannel = async (baseUrl, {teamId = null, type = 'O', pref
* @param {Array} userIds - the two user IDs to be in the direct message
* @return {Object} returns {channel} on success or {error, status} on error
*/
export const apiCreateDirectChannel = async (baseUrl, userIds = []) => {
export const apiCreateDirectChannel = async (baseUrl: string, userIds: string[] = []): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/channels/direct`,
@@ -89,7 +89,7 @@ export const apiCreateDirectChannel = async (baseUrl, userIds = []) => {
* @param {Array} userIds - user IDs to be in the group message channel
* @return {Object} returns {channel} on success or {error, status} on error
*/
export const apiCreateGroupChannel = async (baseUrl, userIds = []) => {
export const apiCreateGroupChannel = async (baseUrl: string, userIds: string[] = []): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/channels/group`,
@@ -110,7 +110,7 @@ export const apiCreateGroupChannel = async (baseUrl, userIds = []) => {
* @param {string} channelName - channel name
* @return {Object} returns {channel} on success or {error, status} on error
*/
export const apiGetChannelByName = async (baseUrl, teamId, channelName) => {
export const apiGetChannelByName = async (baseUrl: string, teamId: string, channelName: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/teams/${teamId}/channels/name/${channelName}`);
@@ -128,7 +128,7 @@ export const apiGetChannelByName = async (baseUrl, teamId, channelName) => {
* @param {string} channelName - channel name
* @return {Object} returns {channel} on success or {error, status} on error
*/
export const apiGetChannelByNameAndTeamName = async (baseUrl, teamName, channelName) => {
export const apiGetChannelByNameAndTeamName = async (baseUrl: string, teamName: string, channelName: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/teams/name/${teamName}/channels/name/${channelName}`);
@@ -146,7 +146,7 @@ export const apiGetChannelByNameAndTeamName = async (baseUrl, teamName, channelN
* @param {string} teamId - The team ID the user belongs to
* @return {Object} returns {channels} on success or {error, status} on error
*/
export const apiGetChannelsForUser = async (baseUrl, userId, teamId) => {
export const apiGetChannelsForUser = async (baseUrl: string, userId: string, teamId: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/users/${userId}/teams/${teamId}/channels`);
@@ -164,7 +164,7 @@ export const apiGetChannelsForUser = async (baseUrl, userId, teamId) => {
* @param {string} channelId - The channel ID that is being viewed
* @return {Object} returns response on success or {error, status} on error
*/
export const apiGetUnreadMessages = async (baseUrl, userId, channelId) => {
export const apiGetUnreadMessages = async (baseUrl: string, userId: string, channelId: string): Promise<any> => {
try {
return await client.get(`${baseUrl}/api/v4/users/${userId}/channels/${channelId}/unread`);
} catch (err) {
@@ -180,7 +180,7 @@ export const apiGetUnreadMessages = async (baseUrl, userId, channelId) => {
* @param {string} userId - The user ID to be removed from channel
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiRemoveUserFromChannel = async (baseUrl, channelId, userId) => {
export const apiRemoveUserFromChannel = async (baseUrl: string, channelId: string, userId: string): Promise<any> => {
try {
const response = await client.delete(
`${baseUrl}/api/v4/channels/${channelId}/members/${userId}`,
@@ -200,7 +200,7 @@ export const apiRemoveUserFromChannel = async (baseUrl, channelId, userId) => {
* @param {string} channelId - The channel ID that is being viewed
* @return {Object} returns {viewed} on success or {error, status} on error
*/
export const apiViewChannel = async (baseUrl, userId, channelId) => {
export const apiViewChannel = async (baseUrl: string, userId: string, channelId: string): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/channels/members/${userId}/view`,
@@ -213,7 +213,7 @@ export const apiViewChannel = async (baseUrl, userId, channelId) => {
}
};
function generateRandomChannel(teamId, type, prefix) {
export const generateRandomChannel = (teamId: string, type: string, prefix: string) => {
const randomId = getRandomId();
return {
@@ -224,7 +224,7 @@ function generateRandomChannel(teamId, type, prefix) {
purpose: `Channel purpose: ${prefix} ${randomId}`,
header: `Channel header: ${prefix} ${randomId}`,
};
}
};
export const Channel = {
apiAddUserToChannel,
@@ -236,6 +236,7 @@ export const Channel = {
apiGetUnreadMessages,
apiRemoveUserFromChannel,
apiViewChannel,
generateRandomChannel,
};
export default Channel;

View File

@@ -2,9 +2,13 @@
// See LICENSE.txt for license information.
import axios from 'axios';
import {wrapper} from 'axios-cookiejar-support';
import {CookieJar} from 'tough-cookie';
export const client = axios.create({
const jar = new CookieJar();
export const client = wrapper(axios.create({
headers: {'X-Requested-With': 'XMLHttpRequest'},
});
jar,
}));
export default client;

View File

@@ -7,7 +7,7 @@ import FormData from 'form-data';
import client from './client';
export const getResponseFromError = (err) => {
export const getResponseFromError = (err: any) => {
const {response} = err;
if (!response) {
const message = `No response from server at "${err.config.baseURL}".
@@ -26,7 +26,7 @@ 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 = {}) => {
export const apiUploadFile = async (name: string, absFilePath: string, requestOptions = {}): Promise<any> => {
if (!fs.existsSync(absFilePath)) {
return {error: {message: `File upload error. "${name}" file does not exist at ${absFilePath}`}};
}

View File

@@ -189,11 +189,11 @@
"ShowFullName": true
},
"SupportSettings": {
"TermsOfServiceLink": "https://about.mattermost.com/default-terms/",
"PrivacyPolicyLink": "https://about.mattermost.com/default-privacy-policy/",
"AboutLink": "https://about.mattermost.com/default-about/",
"HelpLink": "https://about.mattermost.com/default-help/",
"ReportAProblemLink": "https://about.mattermost.com/default-report-a-problem/",
"TermsOfServiceLink": "https://mattermost.com/terms-of-use/",
"PrivacyPolicyLink": "https://mattermost.com/privacy-policy/",
"AboutLink": "https://mattermost.com/default-about/",
"HelpLink": "https://mattermost.com/default-help/",
"ReportAProblemLink": "https://mattermost.com/default-report-a-problem/",
"SupportEmail": "feedback@mattermost.com",
"CustomTermsOfServiceEnabled": false,
"CustomTermsOfServiceReAcceptancePeriod": 365,
@@ -233,8 +233,8 @@
},
"NativeAppSettings": {
"AppDownloadLink": "https://mattermost.com/download/#mattermostApps",
"AndroidAppDownloadLink": "https://about.mattermost.com/mattermost-android-app/",
"IosAppDownloadLink": "https://about.mattermost.com/mattermost-ios-app/"
"AndroidAppDownloadLink": "https://mattermost.com/mattermost-android-app/",
"IosAppDownloadLink": "https://mattermost.com/mattermost-ios-app/"
},
"ClusterSettings": {
"Enable": false

View File

@@ -24,7 +24,7 @@ import {getResponseFromError} from './common';
* @param {string} baseUrl - the base server URL
* @return {string} returns response on success or {error, status} on error
*/
export const apiLDAPSync = async (baseUrl) => {
export const apiLDAPSync = async (baseUrl: string): Promise<any> => {
try {
return await client.post(`${baseUrl}/api/v4/ldap/sync`);
} catch (err) {
@@ -38,7 +38,7 @@ export const apiLDAPSync = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiLDAPTest = async (baseUrl) => {
export const apiLDAPTest = async (baseUrl: string): Promise<any> => {
try {
const response = await client.post(`${baseUrl}/api/v4/ldap/test`);
@@ -52,7 +52,7 @@ export const apiLDAPTest = async (baseUrl) => {
* Check that LDAP server can connect and is synchronized with Mattermost server.
* @param {string} baseUrl - the base server URL
*/
export const apiRequireLDAPServer = async (baseUrl) => {
export const apiRequireLDAPServer = async (baseUrl: string): Promise<any> => {
const {error: testError} = await apiLDAPTest(baseUrl);
jestExpect(testError).toBeUndefined();

View File

@@ -38,12 +38,12 @@ const prepackagedPlugins = [
* Disable non-prepackaged plugins.
* @param {string} baseUrl - the base server URL
*/
export const apiDisableNonPrepackagedPlugins = async (baseUrl) => {
export const apiDisableNonPrepackagedPlugins = async (baseUrl: string): Promise<any> => {
const {plugins} = await apiGetAllPlugins(baseUrl);
if (!plugins) {
return;
}
plugins.active.forEach(async (plugin) => {
plugins.active.forEach(async (plugin: any) => {
if (!prepackagedPlugins.includes(plugin.id)) {
await apiDisablePluginById(baseUrl, plugin.id);
}
@@ -57,7 +57,7 @@ export const apiDisableNonPrepackagedPlugins = async (baseUrl) => {
* @param {string} pluginId - the plugin ID
* @return {Object} returns response on success or {error, status} on error
*/
export const apiDisablePluginById = async (baseUrl, pluginId) => {
export const apiDisablePluginById = async (baseUrl: string, pluginId: string): Promise<any> => {
try {
return await client.post(`${baseUrl}/api/v4/plugins/${encodeURIComponent(pluginId)}/disable`);
} catch (err) {
@@ -72,7 +72,7 @@ export const apiDisablePluginById = async (baseUrl, pluginId) => {
* @param {string} pluginId - the plugin ID
* @return {Object} returns response on success or {error, status} on error
*/
export const apiEnablePluginById = async (baseUrl, pluginId) => {
export const apiEnablePluginById = async (baseUrl: string, pluginId: string): Promise<any> => {
try {
return await client.post(`${baseUrl}/api/v4/plugins/${encodeURIComponent(pluginId)}/enable`);
} catch (err) {
@@ -86,7 +86,7 @@ export const apiEnablePluginById = async (baseUrl, pluginId) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {plugins} on success or {error, status} on error
*/
export const apiGetAllPlugins = async (baseUrl) => {
export const apiGetAllPlugins = async (baseUrl: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/plugins`);
@@ -104,7 +104,7 @@ export const apiGetAllPlugins = async (baseUrl) => {
* @param {string} force - Set to 'true' to overwrite a previously installed plugin with the same ID, if any
* @return {Object} returns {plugin} on success or {error, status} on error
*/
export const apiInstallPluginFromUrl = async (baseUrl, pluginDownloadUrl, force = false) => {
export const apiInstallPluginFromUrl = async (baseUrl: string, pluginDownloadUrl: string, force = false): Promise<any> => {
try {
const response = await client.post(`${baseUrl}/api/v4/plugins/install_from_url?plugin_download_url=${encodeURIComponent(pluginDownloadUrl)}&force=${force}`);
@@ -121,7 +121,7 @@ export const apiInstallPluginFromUrl = async (baseUrl, pluginDownloadUrl, force
* @param {string} pluginId - the plugin ID
* @return {Object} returns response on success or {error, status} on error
*/
export const apiRemovePluginById = async (baseUrl, pluginId) => {
export const apiRemovePluginById = async (baseUrl: string, pluginId: string): Promise<any> => {
try {
return await client.delete(`${baseUrl}/api/v4/plugins/${encodeURIComponent(pluginId)}`);
} catch (err) {
@@ -136,7 +136,7 @@ export const apiRemovePluginById = async (baseUrl, pluginId) => {
* @param {string} filename - the filename of plugin to be uploaded
* @return {Object} returns response on success or {error, status} on error
*/
export const apiUploadPlugin = async (baseUrl, filename) => {
export const apiUploadPlugin = async (baseUrl: string, filename: string): Promise<any> => {
try {
const absFilePath = path.resolve(__dirname, `../../support/fixtures/${filename}`);
return await apiUploadFile('plugin', absFilePath, {url: `${baseUrl}/api/v4/plugins`, method: 'POST'});

View File

@@ -27,7 +27,7 @@ import {getResponseFromError} from './common';
* @param {Date} option.createAt - The date the post is created at
* @return {Object} returns {post} on success or {error, status} on error
*/
export const apiCreatePost = async (baseUrl, {channelId, message, rootId, props = {}, createAt = 0}) => {
export const apiCreatePost = async (baseUrl: string, {channelId, message, rootId, props = {}, createAt = 0}: any): Promise<any> => {
try {
const payload = {
channel_id: channelId,
@@ -51,13 +51,13 @@ export const apiCreatePost = async (baseUrl, {channelId, message, rootId, props
* @param {string} channelId - The channel ID to get the posts for
* @return {Object} returns {posts} on success or {error, status} on error
*/
export const apiGetPostsInChannel = async (baseUrl, channelId) => {
export const apiGetPostsInChannel = async (baseUrl: string, channelId: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/channels/${channelId}/posts`);
const {order, posts} = response.data;
const orderedPosts = order.map((postId) => posts[postId]);
const orderedPosts = order.map((postId: string) => posts[postId]);
return {posts: orderedPosts};
} catch (err) {
@@ -71,7 +71,7 @@ export const apiGetPostsInChannel = async (baseUrl, channelId) => {
* @param {string} channelId - The channel ID to get the last post
* @return {Object} returns {post} on success or {error, status} on error
*/
export const apiGetLastPostInChannel = async (baseUrl, channelId) => {
export const apiGetLastPostInChannel = async (baseUrl: string, channelId: string): Promise<any> => {
const {posts} = await apiGetPostsInChannel(baseUrl, channelId);
return {post: posts[0]};
};
@@ -84,7 +84,7 @@ export const apiGetLastPostInChannel = async (baseUrl, channelId) => {
* @param {Object} postData - data to partially update a post
* @return {Object} returns {post} on success or {error, status} on error
*/
export const apiPatchPost = async (baseUrl, postId, postData) => {
export const apiPatchPost = async (baseUrl: string, postId: string, postData: string): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/posts/${postId}/patch`,

View File

@@ -23,7 +23,7 @@ import {getResponseFromError} from './common';
* @param {string} channelId - the channel id to be favorited
* @return {string} returns {status} on success or {error, status} on error
*/
export const apiSaveFavoriteChannelPreference = (baseUrl, userId, channelId) => {
export const apiSaveFavoriteChannelPreference = (baseUrl: string, userId: string, channelId: string): any => {
const preference = {
user_id: userId,
category: 'favorite_channel',
@@ -41,7 +41,7 @@ export const apiSaveFavoriteChannelPreference = (baseUrl, userId, channelId) =>
* @param {string} nameFormat - one of "username" (default), "nickname_full_name" or "full_name"
* @returns
*/
export const apiSaveTeammateNameDisplayPreference = (baseUrl, userId, nameFormat = 'username') => {
export const apiSaveTeammateNameDisplayPreference = (baseUrl: string, userId: string, nameFormat = 'username'): any => {
const preference = {
user_id: userId,
category: 'display_settings',
@@ -59,7 +59,7 @@ export const apiSaveTeammateNameDisplayPreference = (baseUrl, userId, nameFormat
* @param {Array} orderedTeamIds - ordered array of team IDs
* @return {string} returns {status} on success or {error, status} on error
*/
export const apiSaveTeamsOrderPreference = (baseUrl, userId, orderedTeamIds = []) => {
export const apiSaveTeamsOrderPreference = (baseUrl: string, userId: string, orderedTeamIds: string[] = []): any => {
const preference = {
user_id: userId,
category: 'teams_order',
@@ -78,7 +78,7 @@ export const apiSaveTeamsOrderPreference = (baseUrl, userId, orderedTeamIds = []
* @param {Array} preferences - a list of user's preferences
* @return {string} returns {status} on success or {error, status} on error
*/
export const apiSaveUserPreferences = async (baseUrl, userId, preferences = []) => {
export const apiSaveUserPreferences = async (baseUrl: string, userId: string, preferences: any[] = []): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/users/${userId}/preferences`,

View File

@@ -11,11 +11,11 @@ import User from './user';
* @param {Object} options - may pass options to predefine channel, team and user creation
* @return {Object} returns {channel, team, user} on success or {error, status} on error
*/
export const apiInit = async (baseUrl, {
export const apiInit = async (baseUrl: string, {
channelOptions = {type: 'O', prefix: 'channel'},
teamOptions = {type: 'O', prefix: 'team'},
userOptions = {prefix: 'user'},
} = {}) => {
}: any = {}): Promise<any> => {
const {team} = await Team.apiCreateTeam(baseUrl, teamOptions);
const {channel} = await Channel.apiCreateChannel(baseUrl, {...channelOptions, teamId: team.id});
const {user} = await User.apiCreateUser(baseUrl, userOptions);

View File

@@ -23,7 +23,7 @@ import {getResponseFromError} from './common';
* @param {string} userId - the user ID
* @return {Object} returns {userStatus} on success or {error, status} on error
*/
export const apiGetUserStatus = async (baseUrl, userId) => {
export const apiGetUserStatus = async (baseUrl: string, userId: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/users/${userId}/status`);
@@ -41,7 +41,7 @@ export const apiGetUserStatus = async (baseUrl, userId) => {
* @param {string} status - the user status, can be online, away, offline and dnd
* @return {Object} returns {userStatus} on success or {error, status} on error
*/
export const apiUpdateUserStatus = async (baseUrl, userId, status = 'online') => {
export const apiUpdateUserStatus = async (baseUrl: string, userId: string, status = 'online'): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/users/${userId}/status`,

View File

@@ -3,7 +3,7 @@
import path from 'path';
import testConfig from '@support/test_config';
import {ldapPort, ldapServer} from '@support/test_config';
import merge from 'deepmerge';
import jestExpect from 'expect';
@@ -29,7 +29,7 @@ import defaultServerConfig from './default_config.json';
* Check system health.
* @param {string} baseUrl - the base server URL
*/
export const apiCheckSystemHealth = async (baseUrl) => {
export const apiCheckSystemHealth = async (baseUrl: string): Promise<any> => {
const {data} = await apiPingServerStatus(baseUrl);
jestExpect(data.status).toEqual('OK');
jestExpect(data.database_status).toEqual('OK');
@@ -42,7 +42,7 @@ export const apiCheckSystemHealth = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns response on success or {error, status} on error
*/
export const apiEmailTest = async (baseUrl) => {
export const apiEmailTest = async (baseUrl: string): Promise<any> => {
try {
return await client.post(`${baseUrl}/api/v4/email/test`);
} catch (err) {
@@ -56,7 +56,7 @@ export const apiEmailTest = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {license} on success or {error, status} on error
*/
export const apiGetClientLicense = async (baseUrl) => {
export const apiGetClientLicense = async (baseUrl: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/license/client?format=old`);
@@ -72,7 +72,7 @@ export const apiGetClientLicense = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {config} on success or {error, status} on error
*/
export const apiGetConfig = async (baseUrl) => {
export const apiGetConfig = async (baseUrl: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/config`);
@@ -88,7 +88,7 @@ export const apiGetConfig = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {data} on success or {error, status} on error
*/
export const apiPingServerStatus = async (baseUrl) => {
export const apiPingServerStatus = async (baseUrl: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/system/ping?get_server_status=true`);
return {data: response.data};
@@ -102,7 +102,7 @@ export const apiPingServerStatus = async (baseUrl) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {license} on success or fail when no license
*/
export const apiRequireLicense = async (baseUrl) => {
export const apiRequireLicense = async (baseUrl: string): Promise<any> => {
const {license} = await getClientLicense(baseUrl);
if (license.IsLicensed !== 'true') {
@@ -119,7 +119,7 @@ export const apiRequireLicense = async (baseUrl) => {
* @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 (baseUrl, key = '') => {
export const apiRequireLicenseForFeature = async (baseUrl: string, key = ''): Promise<any> => {
const {license} = await getClientLicense(baseUrl);
if (license.IsLicensed !== 'true') {
@@ -147,7 +147,7 @@ export const apiRequireLicenseForFeature = async (baseUrl, key = '') => {
* Require SMTP server to be running.
* @param {string} baseUrl - the base server URL
*/
export const apiRequireSMTPServer = async (baseUrl) => {
export const apiRequireSMTPServer = async (baseUrl: string) => {
const {status} = await apiEmailTest(baseUrl);
jestExpect(status).toEqual(200);
};
@@ -159,10 +159,10 @@ export const apiRequireSMTPServer = async (baseUrl) => {
* @param {Object} newConfig - specific config to update
* @return {Object} returns {config} on success or {error, status} on error
*/
export const apiUpdateConfig = async (baseUrl, newConfig = {}) => {
export const apiUpdateConfig = async (baseUrl: string, newConfig: any = {}): Promise<any> => {
try {
const {config: currentConfig} = await apiGetConfig(baseUrl);
const config = merge.all([currentConfig, getDefaultConfig(), newConfig]);
const config = merge.all([currentConfig, getDefaultConfig(baseUrl), newConfig]);
const response = await client.put(
`${baseUrl}/api/v4/config`,
@@ -181,7 +181,7 @@ export const apiUpdateConfig = async (baseUrl, newConfig = {}) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns response on success or {error, status} on error
*/
export const apiUploadLicense = async (baseUrl) => {
export const apiUploadLicense = async (baseUrl: string): Promise<any> => {
const absFilePath = path.resolve(__dirname, '../../support/fixtures/mattermost-license.txt');
return apiUploadFile('license', absFilePath, {url: `${baseUrl}/api/v4/license`, method: 'POST'});
};
@@ -191,7 +191,7 @@ export const apiUploadLicense = async (baseUrl) => {
* If no license, try to upload if license file is available at "/support/fixtures/mattermost-license.txt".
* @return {Object} returns {license} on success or upload when no license or get updated license.
*/
async function getClientLicense(baseUrl) {
export const getClientLicense = async (baseUrl: string): Promise<any> => {
const {license} = await apiGetClientLicense(baseUrl);
if (license.IsLicensed === 'true') {
return {license};
@@ -207,19 +207,19 @@ async function getClientLicense(baseUrl) {
// Get an updated client license
const out = await apiGetClientLicense(baseUrl);
return {license: out.license};
}
};
function getDefaultConfig(siteUrl) {
export const getDefaultConfig = (siteUrl: string) => {
const fromEnv = {
LdapSettings: {
LdapServer: testConfig.ldapServer,
LdapPort: testConfig.ldapPort,
LdapServer: ldapServer,
LdapPort: ldapPort,
},
ServiceSettings: {SiteURL: siteUrl},
};
return merge(defaultServerConfig, fromEnv);
}
};
export const System = {
apiCheckSystemHealth,
@@ -232,6 +232,8 @@ export const System = {
apiRequireSMTPServer,
apiUpdateConfig,
apiUploadLicense,
getClientLicense,
getDefaultConfig,
};
export default System;

View File

@@ -27,7 +27,7 @@ import {getResponseFromError} from './common';
* @param {string} teamId - The team ID
* @return {Object} returns {member} on success or {error, status} on error
*/
export const apiAddUserToTeam = async (baseUrl, userId, teamId) => {
export const apiAddUserToTeam = async (baseUrl: string, userId: string, teamId: string): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/teams/${teamId}/members`,
@@ -49,7 +49,7 @@ export const apiAddUserToTeam = async (baseUrl, userId, teamId) => {
* @param {Object} option.team - team object to be created
* @return {Object} returns {team} on success or {error, status} on error
*/
export const apiCreateTeam = async (baseUrl, {type = 'O', prefix = 'team', team = null} = {}) => {
export const apiCreateTeam = async (baseUrl: string, {type = 'O', prefix = 'team', team = null}: any = {}): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/teams`,
@@ -69,7 +69,7 @@ export const apiCreateTeam = async (baseUrl, {type = 'O', prefix = 'team', team
* @param {string} teamId - The team ID
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeleteTeam = async (baseUrl, teamId) => {
export const apiDeleteTeam = async (baseUrl: string, teamId: string): Promise<any> => {
try {
const response = await client.delete(
`${baseUrl}/api/v4/teams/${teamId}`,
@@ -86,13 +86,13 @@ export const apiDeleteTeam = async (baseUrl, teamId) => {
* @param {string} baseUrl - the base server URL
* @param {Array} teams - array of teams
*/
export const apiDeleteTeams = async (baseUrl, teams = []) => {
export const apiDeleteTeams = async (baseUrl: string, teams: any[] = []) => {
let teamArray = teams;
if (!teamArray.length > 0) {
if (teamArray.length === 0) {
({teams: teamArray} = await Team.apiGetTeams(baseUrl));
}
teamArray.forEach(async (team) => {
teamArray.forEach(async (team: any) => {
const {status} = await Team.apiDeleteTeam(baseUrl, team.id);
jestExpect(status).toEqual(200);
});
@@ -106,7 +106,7 @@ export const apiDeleteTeams = async (baseUrl, teams = []) => {
* @param {string} userId - The user ID to be removed from team
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeleteUserFromTeam = async (baseUrl, teamId, userId) => {
export const apiDeleteUserFromTeam = async (baseUrl: string, teamId: string, userId: string): Promise<any> => {
try {
const response = await client.delete(
`${baseUrl}/api/v4/teams/${teamId}/members/${userId}`,
@@ -124,7 +124,7 @@ export const apiDeleteUserFromTeam = async (baseUrl, teamId, userId) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {teams} on success or {error, status} on error
*/
export const apiGetTeams = async (baseUrl) => {
export const apiGetTeams = async (baseUrl: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/teams`);
@@ -141,7 +141,7 @@ export const apiGetTeams = async (baseUrl) => {
* @param {string} userId - The user ID
* @return {Object} returns {teams} on success or {error, status} on error
*/
export const apiGetTeamsForUser = async (baseUrl, userId = 'me') => {
export const apiGetTeamsForUser = async (baseUrl: string, userId = 'me'): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/users/${userId}/teams`);
@@ -164,7 +164,7 @@ export const apiGetTeamsForUser = async (baseUrl, userId = 'me') => {
* @param {boolean} patch.group_constrained - Group constrained
* @return {Object} returns {team} on success or {error, status} on error
*/
export const apiPatchTeam = async (baseUrl, teamId, teamData) => {
export const apiPatchTeam = async (baseUrl: string, teamId: string, teamData: string): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/teams/${teamId}/patch`,
@@ -188,18 +188,18 @@ export const apiPatchTeam = async (baseUrl, teamId, teamData) => {
* @param {boolean} patch.group_constrained - Group constrained
* @param {Array} teams - array of teams
*/
export const apiPatchTeams = async (baseUrl, teamData, teams = []) => {
export const apiPatchTeams = async (baseUrl: string, teamData: any, teams: any[] = []) => {
let teamArray = teams;
if (!teamArray.length > 0) {
if (teamArray.length === 0) {
({teams: teamArray} = await Team.apiGetTeams(baseUrl));
}
teamArray.forEach(async (team) => {
teamArray.forEach(async (team: any) => {
await Team.apiPatchTeam(baseUrl, team.id, teamData);
});
};
function generateRandomTeam(type, prefix) {
export const generateRandomTeam = (type: string, prefix: string) => {
const randomId = getRandomId();
return {
@@ -207,7 +207,7 @@ function generateRandomTeam(type, prefix) {
display_name: `${capitalize(prefix)} ${randomId}`,
type,
};
}
};
export const Team = {
apiAddUserToTeam,
@@ -219,6 +219,7 @@ export const Team = {
apiGetTeamsForUser,
apiPatchTeam,
apiPatchTeams,
generateRandomTeam,
};
export default Team;

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import testConfig from '@support/test_config';
import {adminPassword, adminUsername} from '@support/test_config';
import {getRandomId} from '@support/utils';
import client from './client';
@@ -24,10 +24,10 @@ import {getResponseFromError} from './common';
* @param {string} baseUrl - the base server URL
* @return {Object} returns {user, status} on success or {error, status} on error
*/
export const apiAdminLogin = (baseUrl) => {
export const apiAdminLogin = (baseUrl: string): any => {
return apiLogin(baseUrl, {
username: testConfig.adminUsername,
password: testConfig.adminPassword,
username: adminUsername,
password: adminPassword,
});
};
@@ -39,7 +39,7 @@ export const apiAdminLogin = (baseUrl) => {
* @param {Object} option.user - user object to be created
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiCreateUser = async (baseUrl, {prefix = 'user', user = null} = {}) => {
export const apiCreateUser = async (baseUrl: string, {prefix = 'user', user = null}: any = {}): Promise<any> => {
try {
const newUser = user || generateRandomUser({prefix});
@@ -61,7 +61,7 @@ export const apiCreateUser = async (baseUrl, {prefix = 'user', user = null} = {}
* @param {string} userId - the user ID
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDeactivateUser = async (baseUrl, userId) => {
export const apiDeactivateUser = async (baseUrl: string, userId: string): Promise<any> => {
try {
const response = await client.delete(`${baseUrl}/api/v4/users/${userId}`);
@@ -78,7 +78,7 @@ export const apiDeactivateUser = async (baseUrl, userId) => {
* @param {string} userId - the user ID
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiDemoteUserToGuest = async (baseUrl, userId) => {
export const apiDemoteUserToGuest = async (baseUrl: string, userId: string): Promise<any> => {
try {
const response = await client.post(`${baseUrl}/api/v4/users/${userId}/demote`);
@@ -93,7 +93,7 @@ export const apiDemoteUserToGuest = async (baseUrl, userId) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiGetMe = (baseUrl) => {
export const apiGetMe = (baseUrl: string): any => {
return apiGetUserById(baseUrl, 'me');
};
@@ -104,7 +104,7 @@ export const apiGetMe = (baseUrl) => {
* @param {string} userId - the user ID
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiGetUserById = async (baseUrl, userId) => {
export const apiGetUserById = async (baseUrl: string, userId: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/users/${userId}`);
@@ -121,7 +121,7 @@ export const apiGetUserById = async (baseUrl, userId) => {
* @param {string} username - the username
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiGetUserByUsername = async (baseUrl, username) => {
export const apiGetUserByUsername = async (baseUrl: string, username: string): Promise<any> => {
try {
const response = await client.get(`${baseUrl}/api/v4/users/username/${username}`);
@@ -139,18 +139,14 @@ export const apiGetUserByUsername = async (baseUrl, username) => {
* @param {string} user.password - password of a user
* @return {Object} returns {user, status} on success or {error, status} on error
*/
export const apiLogin = async (baseUrl, user) => {
export const apiLogin = async (baseUrl: string, user: any): Promise<any> => {
try {
const response = await client.post(
`${baseUrl}/api/v4/users/login`,
{login_id: user.username, password: user.password},
);
const {data, headers, status} = response;
// Get MMAUTHTOKEN cookie and attach to the client instance
const [mmAuthToken] = headers['set-cookie'];
client.defaults.headers.Cookie = mmAuthToken;
const {data, status} = response;
return {
status,
@@ -167,11 +163,9 @@ export const apiLogin = async (baseUrl, user) => {
* @param {string} baseUrl - the base server URL
* @return {Object} returns {status} on success
*/
export const apiLogout = async (baseUrl) => {
export const apiLogout = async (baseUrl: string): Promise<any> => {
const response = await client.post(`${baseUrl}/api/v4/users/logout`);
client.defaults.headers.Cookie = '';
return {status: response.status};
};
@@ -181,7 +175,7 @@ export const apiLogout = async (baseUrl) => {
* @param {Object} userData - data to partially update a user
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiPatchMe = (baseUrl, userData) => {
export const apiPatchMe = (baseUrl: string, userData: string): any => {
return apiPatchUser(baseUrl, 'me', userData);
};
@@ -193,7 +187,7 @@ export const apiPatchMe = (baseUrl, userData) => {
* @param {Object} userData - data to partially update a user
* @return {Object} returns {user} on success or {error, status} on error
*/
export const apiPatchUser = async (baseUrl, userId, userData) => {
export const apiPatchUser = async (baseUrl: string, userId: string, userData: any): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/users/${userId}/patch`,
@@ -214,7 +208,7 @@ export const apiPatchUser = async (baseUrl, userId, userData) => {
* @param {boolean} active - use true to set the user active, false for inactive
* @return {Object} returns {status} on success or {error, status} on error
*/
export const apiUpdateUserActiveStatus = async (baseUrl, userId, active) => {
export const apiUpdateUserActiveStatus = async (baseUrl: string, userId: string, active: boolean): Promise<any> => {
try {
const response = await client.put(
`${baseUrl}/api/v4/users/${userId}/active`,

View File

@@ -1,13 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
module.exports = {
serverOneUrl: process.env.SITE_1_URL || (process.env.IOS ? 'http://127.0.0.1:8065' : 'http://10.0.2.2:8065'),
siteOneUrl: process.env.SITE_1_URL || 'http://127.0.0.1:8065',
smtpUrl: process.env.SMTP_URL || 'http://127.0.0.1:9001',
adminEmail: process.env.ADMIN_EMAIL || 'sysadmin@sample.mattermost.com',
adminUsername: process.env.ADMIN_USERNAME || 'sysadmin',
adminPassword: process.env.ADMIN_PASSWORD || 'Sys@dmin-sample1',
ldapServer: process.env.LDAP_SERVER || '127.0.0.1',
ldapPort: process.env.LDAP_PORT || 389,
};

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export const serverOneUrl = process.env.SITE_1_URL || (process.env.IOS ? 'http://127.0.0.1:8065' : 'http://10.0.2.2:8065');
export const siteOneUrl = process.env.SITE_1_URL || 'http://127.0.0.1:8065';
export const serverTwoUrl = process.env.SITE_2_URL || 'https://bitrise02.test.mattermost.cloud';
export const siteTwoUrl = process.env.SITE_2_URL || 'https://bitrise02.test.mattermost.cloud';
export const serverThreeUrl = process.env.SITE_3_URL || 'https://bitrise03.test.mattermost.cloud';
export const siteThreeUrl = process.env.SITE_3_URL || 'https://bitrise03.test.mattermost.cloud';
export const smtpUrl = process.env.SMTP_URL || 'http://127.0.0.1:9001';
export const adminEmail = process.env.ADMIN_EMAIL || 'sysadmin@sample.mattermost.com';
export const adminUsername = process.env.ADMIN_USERNAME || 'sysadmin';
export const adminPassword = process.env.ADMIN_PASSWORD || 'Sys@dmin-sample1';
export const ldapServer = process.env.LDAP_SERVER || '127.0.0.1';
export const ldapPort = process.env.LDAP_PORT || '389';

View File

@@ -5,7 +5,7 @@ import {isAndroid} from '@support/utils';
class Alert {
// alert titles
logoutTitle = (serverDisplayName) => {
logoutTitle = (serverDisplayName: string) => {
const title = `Are you sure you want to log out of ${serverDisplayName}?`;
return isAndroid() ? element(by.text(title)) : element(by.label(title)).atIndex(0);

View File

@@ -4,6 +4,7 @@
import {Alert} from '@support/ui/component';
import {HomeScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class AccountScreen {
testID = {
@@ -15,7 +16,7 @@ class AccountScreen {
logoutAction = element(by.id(this.testID.logoutAction));
toBeVisible = async () => {
await waitFor(this.accountScreen).toBeVisible().withTimeout(timeouts.TEN_SEC);
await waitFor(this.accountScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.accountScreen;
};
@@ -27,7 +28,7 @@ class AccountScreen {
return this.toBeVisible();
};
logout = async (serverDisplayName = null) => {
logout = async (serverDisplayName: string | null = null) => {
await this.logoutAction.tap();
if (serverDisplayName) {
await expect(Alert.logoutTitle(serverDisplayName)).toBeVisible();

View File

@@ -7,16 +7,18 @@ import {timeouts} from '@support/utils';
class ChannelListScreen {
testID = {
channelListScreen: 'channel_list.screen',
serverIcon: 'channel_list.servers.server_icon',
headerTeamDisplayName: 'channel_list_header.team_display_name',
headerServerDisplayName: 'channel_list_header.server_display_name',
};
channelListScreen = element(by.id(this.testID.channelListScreen));
serverIcon = element(by.id(this.testID.serverIcon));
headerTeamDisplayName = element(by.id(this.testID.headerTeamDisplayName));
headerServerDisplayName = element(by.id(this.testID.headerServerDisplayName));
toBeVisible = async () => {
await waitFor(this.channelListScreen).toBeVisible().withTimeout(timeouts.TEN_SEC);
await waitFor(this.channelListScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.channelListScreen;
};

View File

@@ -6,6 +6,7 @@ import {
LoginScreen,
} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class HomeScreen {
testID = {
@@ -33,7 +34,7 @@ class HomeScreen {
return this.toBeVisible();
};
logout = async (serverDisplayName = null) => {
logout = async (serverDisplayName: string | null = null) => {
await AccountScreen.open();
await AccountScreen.logout(serverDisplayName);
await expect(this.channelListTab).not.toBeVisible();

View File

@@ -6,6 +6,7 @@ import ChannelListScreen from './channel_list';
import HomeScreen from './home';
import LoginScreen from './login';
import ServerScreen from './server';
import ServerListScreen from './server_list';
export {
AccountScreen,
@@ -13,4 +14,5 @@ export {
HomeScreen,
LoginScreen,
ServerScreen,
ServerListScreen,
};

View File

@@ -3,6 +3,7 @@
import {ServerScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class LoginScreen {
testID = {
@@ -28,13 +29,13 @@ class LoginScreen {
signinButtonDisabled = element(by.id(this.testID.signinButtonDisabled));
toBeVisible = async () => {
await waitFor(this.loginScreen).toBeVisible().withTimeout(timeouts.TEN_SEC);
await waitFor(this.loginScreen).toExist().withTimeout(timeouts.TEN_SEC);
await waitFor(this.usernameInput).toBeVisible().withTimeout(timeouts.TEN_SEC);
return this.loginScreen;
};
open = async (serverUrl, serverDisplayName) => {
open = async (serverUrl: string, serverDisplayName: string) => {
// # Open login screen
await ServerScreen.connectToServer(serverUrl, serverDisplayName);
@@ -46,7 +47,7 @@ class LoginScreen {
await expect(this.loginScreen).not.toBeVisible();
};
login = async (user = {}) => {
login = async (user: any = {}) => {
await this.toBeVisible();
await this.usernameInput.replaceText(user.username);
await this.passwordInput.replaceText(user.password);

View File

@@ -33,13 +33,13 @@ class ServerScreen {
connectButtonDisabled = element(by.id(this.testID.connectButtonDisabled));
toBeVisible = async () => {
await waitFor(this.serverScreen).toBeVisible().withTimeout(timeouts.TEN_SEC);
await waitFor(this.serverScreen).toExist().withTimeout(timeouts.TEN_SEC);
await waitFor(this.serverUrlInput).toBeVisible().withTimeout(timeouts.TEN_SEC);
return this.serverScreen;
};
connectToServer = async (serverUrl, serverDisplayName) => {
connectToServer = async (serverUrl: string, serverDisplayName: string) => {
await this.toBeVisible();
await this.serverUrlInput.replaceText(serverUrl);
await this.serverDisplayNameInput.replaceText(serverDisplayName);

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ChannelListScreen} from '@support/ui/screen';
import {timeouts} from '@support/utils';
import {expect} from 'detox';
class ServerListScreen {
testID = {
serverListScreen: 'server_list.screen',
serverListTitle: 'server_list.title',
addServerButton: 'server_list.add_a_server.button',
};
serverListScreen = element(by.id(this.testID.serverListScreen));
serverListTitle = element(by.id(this.testID.serverListTitle));
addServerButton = element(by.id(this.testID.addServerButton));
toServerItemTestIdPrefix = (serverDisplayName: string) => {
return `server_list.server_item.${serverDisplayName.replace(/ /g, '_').toLocaleLowerCase()}`;
};
getServerItemActive = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.active`));
};
getServerItemInactive = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.inactive`));
};
getServerItemServerIcon = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.server_icon`));
};
getServerItemEditOption = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.edit.option`));
};
getServerItemRemoveOption = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.remove.option`));
};
getServerItemLoginOption = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.login.option`));
};
getServerItemLogoutOption = (serverDisplayName: string) => {
return element(by.id(`${this.toServerItemTestIdPrefix(serverDisplayName)}.logout.option`));
};
toBeVisible = async () => {
await waitFor(this.serverListScreen).toExist().withTimeout(timeouts.TEN_SEC);
return this.serverListScreen;
};
open = async () => {
// # Open server list screen
await ChannelListScreen.serverIcon.tap();
// # Close tip overlay
await this.serverListScreen.tap({x: 5, y: 10});
return this.toBeVisible();
};
close = async () => {
await this.serverListScreen.tap({x: 5, y: 10});
await expect(this.serverListScreen).not.toBeVisible();
};
}
const serverListScreen = new ServerListScreen();
export default serverListScreen;

View File

@@ -1,18 +1,20 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import testConfig from '@support/test_config';
import {smtpUrl} from '@support/test_config';
import axios from 'axios';
import jestExpect from 'expect';
const currentYear = new Date().getFullYear();
/**
* Get email url.
* @returns {string} email url
*/
export const getEmailUrl = () => {
const smtpUrl = testConfig.smtpUrl || 'http://localhost:9001';
export const getEmailUrl = (): string => {
const smtpUrlBase = smtpUrl || 'http://localhost:9001';
return `${smtpUrl}/api/v1/mailbox`;
return `${smtpUrlBase}/api/v1/mailbox`;
};
/**
@@ -20,7 +22,7 @@ export const getEmailUrl = () => {
* @param {string} userEmail - the destination user email
* @returns {string} email template
*/
export const getEmailResetEmailTemplate = (userEmail) => {
export const getEmailResetEmailTemplate = (userEmail: string): string[] => {
return [
'----------------------',
'You updated your email',
@@ -42,7 +44,7 @@ export const getEmailResetEmailTemplate = (userEmail) => {
* @param {boolean} isGuest - true if guest; otherwise false
* @returns {string} email template
*/
export const getJoinEmailTemplate = (siteUrl, sender, userEmail, team, isGuest = false) => {
export const getJoinEmailTemplate = (siteUrl: string, sender: string, userEmail: string, team: any, isGuest = false): string[] => {
return [
`${sender} invited you to join the ${team.display_name} team.`,
`${isGuest ? 'You were invited as a guest to collaborate with the team' : 'Start collaborating with your team on Mattermost'}`,
@@ -53,7 +55,7 @@ export const getJoinEmailTemplate = (siteUrl, sender, userEmail, team, isGuest =
'Mattermost is a flexible, open source messaging platform that enables secure team collaboration.',
'Learn more ( mattermost.com )',
'',
'© 2021 Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301',
`© ${currentYear} Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301`,
];
};
@@ -68,7 +70,7 @@ export const getJoinEmailTemplate = (siteUrl, sender, userEmail, team, isGuest =
* @param {string} channelDisplayName - the channel display name where user is mentioned
* @@returns {string} email template
*/
export const getMentionEmailTemplate = (siteUrl, sender, message, postId, siteName, teamName, channelDisplayName) => {
export const getMentionEmailTemplate = (siteUrl: string, sender: string, message: string, postId: string, siteName: string, teamName: string, channelDisplayName: string): string[] => {
return [
`@${sender} mentioned you in a message`,
`While you were away, @${sender} mentioned you in the ${channelDisplayName} channel.`,
@@ -84,7 +86,7 @@ export const getMentionEmailTemplate = (siteUrl, sender, message, postId, siteNa
'Want to change your notifications settings?',
`Login to ${siteName} ( ${siteUrl} ) and go to Settings > Notifications`,
'',
'© 2021 Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301',
`© ${currentYear} Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301`,
];
};
@@ -93,7 +95,7 @@ export const getMentionEmailTemplate = (siteUrl, sender, message, postId, siteNa
* @param {string} siteUrl - the site url
* @returns {string} email template
*/
export const getPasswordResetEmailTemplate = (siteUrl) => {
export const getPasswordResetEmailTemplate = (siteUrl: string): string[] => {
return [
'Reset Your Password',
'Click the button below to reset your password. If you didnt request this, you can safely ignore this email.',
@@ -102,7 +104,7 @@ export const getPasswordResetEmailTemplate = (siteUrl) => {
'',
'The password reset link expires in 24 hours.',
'',
'© 2021 Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301',
`© ${currentYear} Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301`,
];
};
@@ -112,7 +114,7 @@ export const getPasswordResetEmailTemplate = (siteUrl) => {
* @param {string} userEmail - the destination user email
* @returns {string} email template
*/
export const getEmailVerifyEmailTemplate = (siteUrl, userEmail) => {
export const getEmailVerifyEmailTemplate = (siteUrl: string, userEmail: string): string[] => {
return [
'Verify your email address',
`Thanks for joining ${siteUrl.split('/')[2]}. ( ${siteUrl} )`,
@@ -123,7 +125,7 @@ export const getEmailVerifyEmailTemplate = (siteUrl, userEmail) => {
'This email address was used to create an account with Mattermost.',
'If it was not you, you can safely ignore this email.',
'',
'© 2021 Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301',
`© ${currentYear} Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301`,
];
};
@@ -135,7 +137,7 @@ export const getEmailVerifyEmailTemplate = (siteUrl, userEmail) => {
* @param {string} teamName - the team name where user is welcome
* @returns {string} email template
*/
export const getWelcomeEmailTemplate = (siteUrl, userEmail, siteName, teamName) => {
export const getWelcomeEmailTemplate = (siteUrl: string, userEmail: string, siteName: string, teamName: string): string[] => {
return [
'Welcome to the team',
`Thanks for joining ${siteUrl.split('/')[2]}. ( ${siteUrl} )`,
@@ -151,7 +153,7 @@ export const getWelcomeEmailTemplate = (siteUrl, userEmail, siteName, teamName)
'',
'Download ( https://mattermost.com/download/#mattermostApps )',
'',
'© 2021 Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301',
`© ${currentYear} Mattermost, Inc. 530 Lytton Avenue, Second floor, Palo Alto, CA, 94301`,
];
};
@@ -160,27 +162,27 @@ export const getWelcomeEmailTemplate = (siteUrl, userEmail, siteName, teamName)
* @param {string} expectedBody - expected email body
* @param {*} actualBody - actual email body
*/
export const verifyEmailBody = (expectedBody, actualBody) => {
export const verifyEmailBody = (expectedBody: string[], actualBody: string[]) => {
jestExpect(expectedBody.length).toEqual(actualBody.length);
for (let i = 0; i < expectedBody.length; i++) {
if (expectedBody[i].includes('skip-local-time-check')) {
if (expectedBody[i]?.includes('skip-local-time-check')) {
continue;
}
if (expectedBody[i].includes('email-verify-link-check')) {
if (expectedBody[i]?.includes('email-verify-link-check')) {
jestExpect(actualBody[i]).toContain('Verify Email');
jestExpect(actualBody[i]).toContain('do_verify_email?token=');
continue;
}
if (expectedBody[i].includes('join-link-check')) {
if (expectedBody[i]?.includes('join-link-check')) {
jestExpect(actualBody[i]).toContain('Join now');
jestExpect(actualBody[i]).toContain('signup_user_complete/?d=');
continue;
}
if (expectedBody[i].includes('reset-password-link-check')) {
if (expectedBody[i]?.includes('reset-password-link-check')) {
jestExpect(actualBody[i]).toContain('Reset Password');
jestExpect(actualBody[i]).toContain('reset_password_complete?token=');
continue;
@@ -195,7 +197,7 @@ export const verifyEmailBody = (expectedBody, actualBody) => {
* @param {string} username - username of email recipient
* @param {string} mailUrl - url of email
*/
export const getRecentEmail = async (username, mailUrl = getEmailUrl()) => {
export const getRecentEmail = async (username: string, mailUrl: string = getEmailUrl()): Promise<any> => {
const mailboxUrl = `${mailUrl}/${username}`;
let response;
let recentEmail;
@@ -203,7 +205,7 @@ export const getRecentEmail = async (username, mailUrl = getEmailUrl()) => {
try {
response = await axios({url: mailboxUrl, method: 'get'});
recentEmail = response.data[response.data.length - 1];
} catch (error) {
} catch (error: any) {
return {status: error.status, data: null};
}
@@ -216,7 +218,7 @@ export const getRecentEmail = async (username, mailUrl = getEmailUrl()) => {
try {
response = await axios({url: mailMessageUrl, method: 'get'});
recentEmailMessage = response.data;
} catch (error) {
} catch (error: any) {
return {status: error.status, data: null};
}
@@ -228,6 +230,6 @@ export const getRecentEmail = async (username, mailUrl = getEmailUrl()) => {
* @param {string} text
* @return {string} split text
*/
export const splitEmailBodyText = (text) => {
export const splitEmailBodyText = (text: string): string[] => {
return text.split('\n').map((d) => d.trim());
};

View File

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import testConfig from '@support/test_config';
import {adminEmail, adminPassword, adminUsername} from '@support/test_config';
import {v4 as uuidv4} from 'uuid';
export * from './email';
@@ -11,7 +11,7 @@ export * from './email';
* @param {number} ms - duration in millisecond
* @return {Promise} promise with timeout
*/
export const wait = async (ms) => {
export const wait = async (ms: number): Promise<any> => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
@@ -19,7 +19,7 @@ export const wait = async (ms) => {
* Check if android.
* @return {boolean} true if android
*/
export const isAndroid = () => {
export const isAndroid = (): boolean => {
return device.getPlatform() === 'android';
};
@@ -27,7 +27,7 @@ export const isAndroid = () => {
* Check if ios.
* @return {boolean} true if ios
*/
export const isIos = () => {
export const isIos = (): boolean => {
return device.getPlatform() === 'ios';
};
@@ -36,7 +36,7 @@ export const isIos = () => {
* @param {number} length - length on random string to return, e.g. 6 (default)
* @return {string} random string
*/
export const getRandomId = (length = 6) => {
export const getRandomId = (length = 6): string => {
const MAX_SUBSTRING_INDEX = 27;
return uuidv4().replace(/-/g, '').substring(MAX_SUBSTRING_INDEX - length, MAX_SUBSTRING_INDEX);
@@ -47,7 +47,7 @@ export const getRandomId = (length = 6) => {
* @param {string} text
* @return {string} capitalized text
*/
export const capitalize = (text) => {
export const capitalize = (text: string): string => {
return text.charAt(0).toUpperCase() + text.slice(1);
};
@@ -56,9 +56,9 @@ export const capitalize = (text) => {
*/
export const getAdminAccount = () => {
return {
username: testConfig.adminUsername,
password: testConfig.adminPassword,
email: testConfig.adminEmail,
username: adminUsername,
password: adminPassword,
email: adminEmail,
};
};

View File

@@ -12,6 +12,7 @@ import {
LoginScreen,
ServerScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Server Login - Connect to Server', () => {
const {

View File

@@ -17,6 +17,7 @@ import {
LoginScreen,
ServerScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Server Login - Login by Email', () => {
const {

View File

@@ -18,6 +18,7 @@ import {
LoginScreen,
ServerScreen,
} from '@support/ui/screen';
import {expect} from 'detox';
describe('Server Login', () => {
const serverOneDisplayName = 'Server 1';

400
detox/package-lock.json generated
View File

@@ -7,23 +7,31 @@
"name": "mattermost-mobile-e2e",
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7.16.7",
"@babel/plugin-transform-modules-commonjs": "7.16.8",
"@babel/plugin-transform-modules-commonjs": "7.17.7",
"@babel/plugin-transform-runtime": "7.17.0",
"@babel/preset-env": "7.16.11",
"axios": "0.26.0",
"@types/jest": "27.4.1",
"@types/tough-cookie": "4.0.1",
"@types/uuid": "8.3.4",
"axios": "0.26.1",
"axios-cookiejar-support": "2.0.4",
"babel-jest": "27.5.1",
"babel-plugin-module-resolver": "4.1.0",
"client-oauth2": "4.3.3",
"deepmerge": "4.2.2",
"detox": "19.4.5",
"detox": "19.5.7",
"form-data": "4.0.0",
"jest": "27.5.1",
"jest-circus": "27.5.1",
"jest-cli": "27.5.1",
"jest-html-reporters": "3.0.5",
"jest-html-reporters": "3.0.6",
"jest-junit": "13.0.0",
"moment-timezone": "0.5.34",
"sanitize-filename": "1.6.3",
"tough-cookie": "4.0.0",
"ts-jest": "27.1.3",
"tslib": "2.3.1",
"typescript": "4.6.2",
"uuid": "8.3.2"
}
},
@@ -290,19 +298,19 @@
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz",
"integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-module-imports": "^7.16.7",
"@babel/helper-simple-access": "^7.16.7",
"@babel/helper-simple-access": "^7.17.7",
"@babel/helper-split-export-declaration": "^7.16.7",
"@babel/helper-validator-identifier": "^7.16.7",
"@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7",
"@babel/types": "^7.16.7"
"@babel/traverse": "^7.17.3",
"@babel/types": "^7.17.0"
},
"engines": {
"node": ">=6.9.0"
@@ -360,12 +368,12 @@
}
},
"node_modules/@babel/helper-simple-access": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
"integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz",
"integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==",
"dev": true,
"dependencies": {
"@babel/types": "^7.16.7"
"@babel/types": "^7.17.0"
},
"engines": {
"node": ">=6.9.0"
@@ -1205,14 +1213,14 @@
}
},
"node_modules/@babel/plugin-transform-modules-commonjs": {
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
"integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz",
"integrity": "sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==",
"dev": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.16.7",
"@babel/helper-module-transforms": "^7.17.7",
"@babel/helper-plugin-utils": "^7.16.7",
"@babel/helper-simple-access": "^7.16.7",
"@babel/helper-simple-access": "^7.17.7",
"babel-plugin-dynamic-import-node": "^2.3.3"
},
"engines": {
@@ -2434,6 +2442,16 @@
"@types/istanbul-lib-report": "*"
}
},
"node_modules/@types/jest": {
"version": "27.4.1",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz",
"integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==",
"dev": true,
"dependencies": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"node_modules/@types/node": {
"version": "17.0.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz",
@@ -2453,9 +2471,15 @@
"dev": true
},
"node_modules/@types/tough-cookie": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.8.tgz",
"integrity": "sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz",
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"node_modules/@types/yargs": {
@@ -2641,14 +2665,30 @@
}
},
"node_modules/axios": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
"integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.8"
}
},
"node_modules/axios-cookiejar-support": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.4.tgz",
"integrity": "sha512-N4MwaEp5zCAv+wIp5OFZOPiD2qXCCnx21mMQu7yvO8E9j6YlZWazEHXpz7iJlk6HhZ8vh09ujYJJ594H+iVKmA==",
"dev": true,
"dependencies": {
"http-cookie-agent": "^1.0.2"
},
"engines": {
"node": ">=12.19.0 <13.0.0 || >=14.5.0"
},
"peerDependencies": {
"axios": ">=0.20.0",
"tough-cookie": ">=4.0.0"
}
},
"node_modules/babel-jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz",
@@ -2955,6 +2995,18 @@
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/bs-logger": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
"integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
"dev": true,
"dependencies": {
"fast-json-stable-stringify": "2.x"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -3389,9 +3441,9 @@
}
},
"node_modules/detox": {
"version": "19.4.5",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.4.5.tgz",
"integrity": "sha512-kMHxNn3I9uTxOzIX4CTymI9qHRLn90xzuM/QhqHNeUH3AEDFtUmlJpcL86GmPO/VLWafcJScia9jqUiKveNAqg==",
"version": "19.5.7",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.7.tgz",
"integrity": "sha512-vLd5eySM/zjaWLJGgbtx4g7qA3JZLCZHVz4n/AphNFFW3T3qiyh7HfIYeoBoZanjjyC1k3iuw2UshpBRlHZuGA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -4066,6 +4118,21 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/http-cookie-agent": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.5.tgz",
"integrity": "sha512-X8QM/rGPu/cb7A37uNLuz+PZfkmlQ9PycDD+/QsmqICXBd9grKWdWKMzg/BDkzxIbV+P/FYTsKZn08KcXgbLsQ==",
"dev": true,
"dependencies": {
"agent-base": "^6.0.2"
},
"engines": {
"node": ">=12.19.0 <13.0.0 || >=14.5.0"
},
"peerDependencies": {
"tough-cookie": "^4.0.0"
}
},
"node_modules/http-proxy-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
@@ -5039,9 +5106,9 @@
}
},
"node_modules/jest-html-reporters": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/jest-html-reporters/-/jest-html-reporters-3.0.5.tgz",
"integrity": "sha512-xLXOtpbDW33F7xrnWLR9YPvp62MfrULdT6G/jOaQJ8E4+JTu7i++OkpdpFgfNdMxjwde1xQESSRyASRKasUEDQ==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/jest-html-reporters/-/jest-html-reporters-3.0.6.tgz",
"integrity": "sha512-snTlUuZ0FyFmXEkYrNiCH1Zym/u3owI45yG24morKmVJSlTmcjZsaEtbbmL58buxj2Bo6NWukJFaFX7w2aGkXA==",
"dev": true,
"dependencies": {
"fs-extra": "^9.0.1",
@@ -6383,6 +6450,12 @@
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
},
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -7291,6 +7364,12 @@
"servie": "^4.0.0"
}
},
"node_modules/popsicle-cookie-jar/node_modules/@types/tough-cookie": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.8.tgz",
"integrity": "sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg==",
"dev": true
},
"node_modules/popsicle-cookie-jar/node_modules/tough-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
@@ -8142,6 +8221,89 @@
"integrity": "sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==",
"dev": true
},
"node_modules/ts-jest": {
"version": "27.1.3",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz",
"integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==",
"dev": true,
"dependencies": {
"bs-logger": "0.x",
"fast-json-stable-stringify": "2.x",
"jest-util": "^27.0.0",
"json5": "2.x",
"lodash.memoize": "4.x",
"make-error": "1.x",
"semver": "7.x",
"yargs-parser": "20.x"
},
"bin": {
"ts-jest": "cli.js"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
},
"peerDependencies": {
"@babel/core": ">=7.0.0-beta.0 <8",
"@types/jest": "^27.0.0",
"babel-jest": ">=27.0.0 <28",
"esbuild": "~0.14.0",
"jest": "^27.0.0",
"typescript": ">=3.8 <5.0"
},
"peerDependenciesMeta": {
"@babel/core": {
"optional": true
},
"@types/jest": {
"optional": true
},
"babel-jest": {
"optional": true
},
"esbuild": {
"optional": true
}
}
},
"node_modules/ts-jest/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ts-jest/node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ts-jest/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"dev": true
},
"node_modules/type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -8184,6 +8346,19 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/typescript": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
"integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@@ -8763,19 +8938,19 @@
}
},
"@babel/helper-module-transforms": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
"integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz",
"integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==",
"dev": true,
"requires": {
"@babel/helper-environment-visitor": "^7.16.7",
"@babel/helper-module-imports": "^7.16.7",
"@babel/helper-simple-access": "^7.16.7",
"@babel/helper-simple-access": "^7.17.7",
"@babel/helper-split-export-declaration": "^7.16.7",
"@babel/helper-validator-identifier": "^7.16.7",
"@babel/template": "^7.16.7",
"@babel/traverse": "^7.16.7",
"@babel/types": "^7.16.7"
"@babel/traverse": "^7.17.3",
"@babel/types": "^7.17.0"
}
},
"@babel/helper-optimise-call-expression": {
@@ -8818,12 +8993,12 @@
}
},
"@babel/helper-simple-access": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
"integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz",
"integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==",
"dev": true,
"requires": {
"@babel/types": "^7.16.7"
"@babel/types": "^7.17.0"
}
},
"@babel/helper-skip-transparent-expression-wrappers": {
@@ -9378,14 +9553,14 @@
}
},
"@babel/plugin-transform-modules-commonjs": {
"version": "7.16.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz",
"integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==",
"version": "7.17.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz",
"integrity": "sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.16.7",
"@babel/helper-module-transforms": "^7.17.7",
"@babel/helper-plugin-utils": "^7.16.7",
"@babel/helper-simple-access": "^7.16.7",
"@babel/helper-simple-access": "^7.17.7",
"babel-plugin-dynamic-import-node": "^2.3.3"
}
},
@@ -10315,6 +10490,16 @@
"@types/istanbul-lib-report": "*"
}
},
"@types/jest": {
"version": "27.4.1",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz",
"integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==",
"dev": true,
"requires": {
"jest-matcher-utils": "^27.0.0",
"pretty-format": "^27.0.0"
}
},
"@types/node": {
"version": "17.0.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz",
@@ -10334,9 +10519,15 @@
"dev": true
},
"@types/tough-cookie": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.8.tgz",
"integrity": "sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz",
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true
},
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"@types/yargs": {
@@ -10481,14 +10672,23 @@
"dev": true
},
"axios": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
"integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dev": true,
"requires": {
"follow-redirects": "^1.14.8"
}
},
"axios-cookiejar-support": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.4.tgz",
"integrity": "sha512-N4MwaEp5zCAv+wIp5OFZOPiD2qXCCnx21mMQu7yvO8E9j6YlZWazEHXpz7iJlk6HhZ8vh09ujYJJ594H+iVKmA==",
"dev": true,
"requires": {
"http-cookie-agent": "^1.0.2"
}
},
"babel-jest": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz",
@@ -10727,6 +10927,15 @@
"picocolors": "^1.0.0"
}
},
"bs-logger": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
"integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
"dev": true,
"requires": {
"fast-json-stable-stringify": "2.x"
}
},
"bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -11070,9 +11279,9 @@
"dev": true
},
"detox": {
"version": "19.4.5",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.4.5.tgz",
"integrity": "sha512-kMHxNn3I9uTxOzIX4CTymI9qHRLn90xzuM/QhqHNeUH3AEDFtUmlJpcL86GmPO/VLWafcJScia9jqUiKveNAqg==",
"version": "19.5.7",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.7.tgz",
"integrity": "sha512-vLd5eySM/zjaWLJGgbtx4g7qA3JZLCZHVz4n/AphNFFW3T3qiyh7HfIYeoBoZanjjyC1k3iuw2UshpBRlHZuGA==",
"dev": true,
"requires": {
"ajv": "^8.6.3",
@@ -11565,6 +11774,15 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"http-cookie-agent": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.5.tgz",
"integrity": "sha512-X8QM/rGPu/cb7A37uNLuz+PZfkmlQ9PycDD+/QsmqICXBd9grKWdWKMzg/BDkzxIbV+P/FYTsKZn08KcXgbLsQ==",
"dev": true,
"requires": {
"agent-base": "^6.0.2"
}
},
"http-proxy-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
@@ -12280,9 +12498,9 @@
}
},
"jest-html-reporters": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/jest-html-reporters/-/jest-html-reporters-3.0.5.tgz",
"integrity": "sha512-xLXOtpbDW33F7xrnWLR9YPvp62MfrULdT6G/jOaQJ8E4+JTu7i++OkpdpFgfNdMxjwde1xQESSRyASRKasUEDQ==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/jest-html-reporters/-/jest-html-reporters-3.0.6.tgz",
"integrity": "sha512-snTlUuZ0FyFmXEkYrNiCH1Zym/u3owI45yG24morKmVJSlTmcjZsaEtbbmL58buxj2Bo6NWukJFaFX7w2aGkXA==",
"dev": true,
"requires": {
"fs-extra": "^9.0.1",
@@ -13306,6 +13524,12 @@
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
},
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -13987,6 +14211,12 @@
"tough-cookie": "^3.0.1"
},
"dependencies": {
"@types/tough-cookie": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.8.tgz",
"integrity": "sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg==",
"dev": true
},
"tough-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
@@ -14649,6 +14879,54 @@
"integrity": "sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==",
"dev": true
},
"ts-jest": {
"version": "27.1.3",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz",
"integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==",
"dev": true,
"requires": {
"bs-logger": "0.x",
"fast-json-stable-stringify": "2.x",
"jest-util": "^27.0.0",
"json5": "2.x",
"lodash.memoize": "4.x",
"make-error": "1.x",
"semver": "7.x",
"yargs-parser": "20.x"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
}
}
},
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
"dev": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -14679,6 +14957,12 @@
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
"integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
"dev": true
},
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",

View File

@@ -5,23 +5,31 @@
"author": "Mattermost, Inc.",
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7.16.7",
"@babel/plugin-transform-modules-commonjs": "7.16.8",
"@babel/plugin-transform-modules-commonjs": "7.17.7",
"@babel/plugin-transform-runtime": "7.17.0",
"@babel/preset-env": "7.16.11",
"axios": "0.26.0",
"@types/jest": "27.4.1",
"@types/tough-cookie": "4.0.1",
"@types/uuid": "8.3.4",
"axios": "0.26.1",
"axios-cookiejar-support": "2.0.4",
"babel-jest": "27.5.1",
"babel-plugin-module-resolver": "4.1.0",
"client-oauth2": "4.3.3",
"deepmerge": "4.2.2",
"detox": "19.4.5",
"detox": "19.5.7",
"form-data": "4.0.0",
"jest": "27.5.1",
"jest-circus": "27.5.1",
"jest-cli": "27.5.1",
"jest-html-reporters": "3.0.5",
"jest-html-reporters": "3.0.6",
"jest-junit": "13.0.0",
"moment-timezone": "0.5.34",
"sanitize-filename": "1.6.3",
"tough-cookie": "4.0.0",
"ts-jest": "27.1.3",
"tslib": "2.3.1",
"typescript": "4.6.2",
"uuid": "8.3.2"
},
"scripts": {
@@ -33,11 +41,9 @@
"e2e:ios-test": "IOS=true detox test -c ios.sim.debug",
"e2e:ios-build-release": "detox build -c ios.sim.release",
"e2e:ios-test-release": "IOS=true detox test -c ios.sim.release --record-logs failing --take-screenshots failing",
"start:webhook": "node webhook_server.js"
},
"jest": {
"transform": {
"^.+\\.js?$": "babel-jest"
}
"check": "npm run lint && npm run tsc",
"lint": "eslint --ignore-path .gitignore --ignore-pattern node_modules --quiet .",
"start:webhook": "node webhook_server.js",
"tsc": "NODE_OPTIONS=--max_old_space_size=12000 tsc --noEmit"
}
}

29
detox/tsconfig.json Normal file
View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
"target": "esnext",
"lib": [
"es6", "ES2019"
],
"importHelpers": true,
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@support/*": ["e2e/support/*"],
},
"types": ["node", "jest", "detox"]
},
"include": [
"e2e/**/*.ts",
]
}

View File

@@ -7,8 +7,8 @@ const axios = require('axios');
const ClientOAuth2 = require('client-oauth2');
const express = require('express');
const postMessageAs = require('./e2e/plugins/post_message_as');
const webhookUtils = require('./e2e/utils/webhook_utils');
const postMessageAs = require('./utils/post_message_as');
const webhookUtils = require('./utils/webhook_utils');
const port = 3000;
const {

236
package-lock.json generated
View File

@@ -125,15 +125,19 @@
"@types/semver": "7.3.9",
"@types/shallow-equals": "1.0.0",
"@types/tinycolor2": "1.4.3",
"@types/tough-cookie": "4.0.1",
"@types/url-parse": "1.4.8",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.13.0",
"@typescript-eslint/parser": "5.13.0",
"axios": "0.26.1",
"axios-cookiejar-support": "2.0.4",
"babel-jest": "27.5.1",
"babel-loader": "8.2.3",
"babel-plugin-module-resolver": "4.1.0",
"babel-plugin-transform-remove-console": "6.9.4",
"deep-freeze": "0.0.1",
"detox": "19.5.1",
"detox": "19.5.7",
"eslint": "8.10.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.25.4",
@@ -153,10 +157,12 @@
"patch-package": "6.4.7",
"react-native-svg-transformer": "1.0.0",
"react-test-renderer": "17.0.2",
"tough-cookie": "4.0.0",
"ts-jest": "27.1.3",
"typescript": "4.5.5",
"underscore": "1.13.2",
"util": "0.12.4"
"util": "0.12.4",
"uuid": "8.3.2"
}
},
"node_modules/@ampproject/remapping": {
@@ -5929,12 +5935,24 @@
"integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==",
"dev": true
},
"node_modules/@types/tough-cookie": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz",
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true
},
"node_modules/@types/url-parse": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
"integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"node_modules/@types/yargs": {
"version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
@@ -7081,6 +7099,31 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.8"
}
},
"node_modules/axios-cookiejar-support": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.4.tgz",
"integrity": "sha512-N4MwaEp5zCAv+wIp5OFZOPiD2qXCCnx21mMQu7yvO8E9j6YlZWazEHXpz7iJlk6HhZ8vh09ujYJJ594H+iVKmA==",
"dev": true,
"dependencies": {
"http-cookie-agent": "^1.0.2"
},
"engines": {
"node": ">=12.19.0 <13.0.0 || >=14.5.0"
},
"peerDependencies": {
"axios": ">=0.20.0",
"tough-cookie": ">=4.0.0"
}
},
"node_modules/babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@@ -9240,9 +9283,9 @@
}
},
"node_modules/detox": {
"version": "19.5.1",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.1.tgz",
"integrity": "sha512-wOWXRJffpxy1i+QtJAeb5pbo9Wli/L+tHaEcglFVDsTJ0ekjHAfgemY7XXWnaGWkphb0WDvhwfPaaO3o9TpCwg==",
"version": "19.5.7",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.7.tgz",
"integrity": "sha512-vLd5eySM/zjaWLJGgbtx4g7qA3JZLCZHVz4n/AphNFFW3T3qiyh7HfIYeoBoZanjjyC1k3iuw2UshpBRlHZuGA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -10960,6 +11003,15 @@
"expo": "*"
}
},
"node_modules/expo-constants/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/expo-error-recovery": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/expo-error-recovery/-/expo-error-recovery-3.0.5.tgz",
@@ -10981,6 +11033,15 @@
"expo": "*"
}
},
"node_modules/expo-file-system/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/expo-font": {
"version": "10.0.5",
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-10.0.5.tgz",
@@ -11339,6 +11400,15 @@
"node": ">=8"
}
},
"node_modules/expo/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -11817,6 +11887,26 @@
"readable-stream": "^2.3.6"
}
},
"node_modules/follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/fontello-batch-cli": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fontello-batch-cli/-/fontello-batch-cli-4.0.0.tgz",
@@ -12516,6 +12606,21 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/http-cookie-agent": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.5.tgz",
"integrity": "sha512-X8QM/rGPu/cb7A37uNLuz+PZfkmlQ9PycDD+/QsmqICXBd9grKWdWKMzg/BDkzxIbV+P/FYTsKZn08KcXgbLsQ==",
"dev": true,
"dependencies": {
"agent-base": "^6.0.2"
},
"engines": {
"node": ">=12.19.0 <13.0.0 || >=14.5.0"
},
"peerDependencies": {
"tough-cookie": "^4.0.0"
}
},
"node_modules/http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
@@ -22251,6 +22356,16 @@
"node": ">=4"
}
},
"node_modules/tempfile/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/terminal-link": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
@@ -23172,12 +23287,12 @@
}
},
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "bin/uuid"
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": {
@@ -24165,6 +24280,15 @@
"node": ">=6.0.0"
}
},
"node_modules/xcode/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/xdate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/xdate/-/xdate-0.8.2.tgz",
@@ -28628,12 +28752,24 @@
"integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==",
"dev": true
},
"@types/tough-cookie": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz",
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true
},
"@types/url-parse": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.8.tgz",
"integrity": "sha512-zqqcGKyNWgTLFBxmaexGUKQyWqeG7HjXj20EuQJSJWwXe54BjX0ihIo5cJB9yAQzH8dNugJ9GvkBYMjPXs/PJw==",
"dev": true
},
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"@types/yargs": {
"version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
@@ -29498,6 +29634,24 @@
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw=="
},
"axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dev": true,
"requires": {
"follow-redirects": "^1.14.8"
}
},
"axios-cookiejar-support": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.4.tgz",
"integrity": "sha512-N4MwaEp5zCAv+wIp5OFZOPiD2qXCCnx21mMQu7yvO8E9j6YlZWazEHXpz7iJlk6HhZ8vh09ujYJJ594H+iVKmA==",
"dev": true,
"requires": {
"http-cookie-agent": "^1.0.2"
}
},
"babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@@ -31269,9 +31423,9 @@
"dev": true
},
"detox": {
"version": "19.5.1",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.1.tgz",
"integrity": "sha512-wOWXRJffpxy1i+QtJAeb5pbo9Wli/L+tHaEcglFVDsTJ0ekjHAfgemY7XXWnaGWkphb0WDvhwfPaaO3o9TpCwg==",
"version": "19.5.7",
"resolved": "https://registry.npmjs.org/detox/-/detox-19.5.7.tgz",
"integrity": "sha512-vLd5eySM/zjaWLJGgbtx4g7qA3JZLCZHVz4n/AphNFFW3T3qiyh7HfIYeoBoZanjjyC1k3iuw2UshpBRlHZuGA==",
"dev": true,
"requires": {
"ajv": "^8.6.3",
@@ -32655,6 +32809,11 @@
"requires": {
"has-flag": "^4.0.0"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
@@ -32683,6 +32842,13 @@
"requires": {
"@expo/config": "^6.0.6",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"expo-error-recovery": {
@@ -32699,6 +32865,13 @@
"requires": {
"@expo/config-plugins": "^4.0.2",
"uuid": "^3.4.0"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"expo-font": {
@@ -33271,6 +33444,12 @@
"readable-stream": "^2.3.6"
}
},
"follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
"dev": true
},
"fontello-batch-cli": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fontello-batch-cli/-/fontello-batch-cli-4.0.0.tgz",
@@ -33802,6 +33981,15 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"http-cookie-agent": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.5.tgz",
"integrity": "sha512-X8QM/rGPu/cb7A37uNLuz+PZfkmlQ9PycDD+/QsmqICXBd9grKWdWKMzg/BDkzxIbV+P/FYTsKZn08KcXgbLsQ==",
"dev": true,
"requires": {
"agent-base": "^6.0.2"
}
},
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
@@ -41446,6 +41634,14 @@
"requires": {
"temp-dir": "^1.0.0",
"uuid": "^3.0.1"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
}
}
},
"terminal-link": {
@@ -42180,9 +42376,10 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
"v8-compile-cache": {
"version": "2.3.0",
@@ -42972,6 +43169,13 @@
"requires": {
"simple-plist": "^1.0.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"xdate": {

View File

@@ -122,15 +122,19 @@
"@types/semver": "7.3.9",
"@types/shallow-equals": "1.0.0",
"@types/tinycolor2": "1.4.3",
"@types/tough-cookie": "4.0.1",
"@types/url-parse": "1.4.8",
"@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.13.0",
"@typescript-eslint/parser": "5.13.0",
"axios": "0.26.1",
"axios-cookiejar-support": "2.0.4",
"babel-jest": "27.5.1",
"babel-loader": "8.2.3",
"babel-plugin-module-resolver": "4.1.0",
"babel-plugin-transform-remove-console": "6.9.4",
"deep-freeze": "0.0.1",
"detox": "19.5.1",
"detox": "19.5.7",
"eslint": "8.10.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.25.4",
@@ -150,10 +154,12 @@
"patch-package": "6.4.7",
"react-native-svg-transformer": "1.0.0",
"react-test-renderer": "17.0.2",
"tough-cookie": "4.0.0",
"ts-jest": "27.1.3",
"typescript": "4.5.5",
"underscore": "1.13.2",
"util": "0.12.4"
"util": "0.12.4",
"uuid": "8.3.2"
},
"scripts": {
"android": "react-native run-android",

View File

@@ -53,6 +53,7 @@
"@share/*": ["share_extension/*"],
"@store": ["app/store/index"],
"@store/*": ["app/store/*"],
"@support/*": ["detox/e2e/support/*"],
"@telemetry/*": ["/app/telemetry/*"],
"@typings/*": ["types/*"],
"@test/*": ["test/*"],