• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / gui / 951400782

pending completion
951400782

Pull #3900

gitlab-ci

web-flow
chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.16.5 to 5.17.0.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.16.5...v5.17.0)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #3900: chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

4446 of 6414 branches covered (69.32%)

8342 of 10084 relevant lines covered (82.73%)

186.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.34
/src/js/actions/onboardingActions.js
1
// Copyright 2020 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
import Cookies from 'universal-cookie';
15

16
import { DEVICE_STATES } from '../constants/deviceConstants';
17
import {
18
  SET_DEMO_ARTIFACT_PORT,
19
  SET_ONBOARDING_APPROACH,
20
  SET_ONBOARDING_ARTIFACT_INCLUDED,
21
  SET_ONBOARDING_COMPLETE,
22
  SET_ONBOARDING_DEVICE_TYPE,
23
  SET_ONBOARDING_PROGRESS,
24
  SET_SHOW_CREATE_ARTIFACT,
25
  SET_SHOW_ONBOARDING_HELP,
26
  SET_SHOW_ONBOARDING_HELP_DIALOG,
27
  onboardingSteps as onboardingStepNames
28
} from '../constants/onboardingConstants';
29
import { SET_SHOW_HELP } from '../constants/userConstants';
30
import { getDemoDeviceAddress } from '../helpers';
31
import { getUserCapabilities, getUserSettings } from '../selectors';
32
import Tracking from '../tracking';
33
import { applyOnboardingFallbacks, onboardingSteps } from '../utils/onboardingmanager';
34
import { saveUserSettings } from './userActions';
35

36
const cookies = new Cookies();
187✔
37

38
const getCurrentOnboardingState = state => {
187✔
39
  const { showTipsDialog, showCreateArtifactDialog, ...onboardingState } = state.onboarding; // eslint-disable-line no-unused-vars
31✔
40
  const { onboarding = {} } = getUserSettings(state);
31!
41
  return { ...onboardingState, ...onboarding };
31✔
42
};
43

44
const deductOnboardingState = ({ devicesById, devicesByStatus, onboardingState, pastDeployments, releases, userCapabilities, userId }) => {
187✔
45
  const { canDeploy, canManageDevices, canReadDeployments, canReadDevices, canReadReleases, canUploadReleases } = userCapabilities;
8✔
46
  const userCookie = cookies.get(`${userId}-onboarded`);
8✔
47
  const acceptedDevices = devicesByStatus[DEVICE_STATES.accepted].deviceIds;
8✔
48
  const pendingDevices = devicesByStatus[DEVICE_STATES.pending].deviceIds;
8✔
49
  let deviceType = onboardingState.deviceType ?? [];
8✔
50
  deviceType =
8✔
51
    !deviceType.length && acceptedDevices.length && devicesById[acceptedDevices[0]].hasOwnProperty('attributes')
32!
52
      ? devicesById[acceptedDevices[0]].attributes.device_type
53
      : deviceType;
54
  const progress = applyOnboardingFallbacks(onboardingState.progress || determineProgress(acceptedDevices, pendingDevices, releases, pastDeployments));
8✔
55
  return {
8✔
56
    complete: !!(
57
      Boolean(userCookie) ||
90!
58
      onboardingState.complete ||
59
      (acceptedDevices.length > 1 && pendingDevices.length > 0 && releases.length > 1 && pastDeployments.length > 1) ||
60
      (acceptedDevices.length >= 1 && releases.length >= 2 && pastDeployments.length > 2) ||
61
      (acceptedDevices.length >= 1 && pendingDevices.length > 0 && releases.length >= 2 && pastDeployments.length >= 2) ||
62
      Object.keys(onboardingSteps).findIndex(step => step === progress) >= Object.keys(onboardingSteps).length - 1 ||
54✔
63
      onboardingState.disable ||
64
      ![canDeploy, canManageDevices, canReadDeployments, canReadDevices, canReadReleases, canUploadReleases].every(i => i)
36✔
65
    ),
66
    showTips: onboardingState.showTips != null ? onboardingState.showTips : true,
8!
67
    deviceType,
68
    approach: onboardingState.approach || (deviceType.some(type => type.startsWith('qemu')) ? 'virtual' : 'physical'),
8!
69
    artifactIncluded: onboardingState.artifactIncluded,
70
    progress
71
  };
72
};
73

74
export const getOnboardingState = () => (dispatch, getState) => {
187✔
75
  const store = getState();
8✔
76
  let onboardingState = getCurrentOnboardingState(store);
8✔
77
  if (!onboardingState.complete) {
8!
78
    const userId = getState().users.currentUser;
8✔
79
    onboardingState = deductOnboardingState({
8✔
80
      devicesById: store.devices.byId,
81
      devicesByStatus: store.devices.byStatus,
82
      onboardingState,
83
      pastDeployments: store.deployments.byStatus.finished.deploymentIds,
84
      releases: Object.values(store.releases.byId),
85
      userCapabilities: getUserCapabilities(store),
86
      userId
87
    });
88
  }
89
  onboardingState.progress = onboardingState.progress || onboardingStepNames.ONBOARDING_START;
8!
90
  const demoDeviceAddress = `http://${getDemoDeviceAddress(Object.values(store.devices.byId), onboardingState.approach)}`;
8✔
91
  onboardingState.address = store.onboarding.demoArtifactPort ? `${demoDeviceAddress}:${store.onboarding.demoArtifactPort}` : demoDeviceAddress;
8!
92
  const progress = Object.keys(onboardingSteps).findIndex(step => step === onboardingStepNames.ARTIFACT_CREATION_DIALOG);
176✔
93
  const currentProgress = Object.keys(onboardingSteps).findIndex(step => step === onboardingState.progress);
112✔
94
  onboardingState.showArtifactCreation = Math.abs(currentProgress - progress) <= 1;
8✔
95
  if (onboardingState.showArtifactCreation && !onboardingState.complete && onboardingState.showTips && store.users.showHelptips) {
8!
96
    dispatch(setShowCreateArtifactDialog(true));
×
97
    onboardingState.progress = onboardingStepNames.ARTIFACT_CREATION_DIALOG;
×
98
    // although it would be more appropriate to do this in the app component, this happens here because in the app component we would need to track
99
    // redirects, if we want to still allow navigation across the UI while the dialog is visible
100
    if (!window.location.pathname.includes('/ui/releases')) {
×
101
      window.location.replace('/ui/releases');
×
102
    }
103
  }
104
  return Promise.resolve(dispatch(setOnboardingState(onboardingState)));
8✔
105
};
106

107
export const setShowOnboardingHelp =
108
  (show, update = true) =>
187✔
109
  (dispatch, getState) => {
14✔
110
    let tasks = [dispatch({ type: SET_SHOW_ONBOARDING_HELP, show })];
14✔
111
    if (update) {
14✔
112
      const { onboarding = {} } = getUserSettings(getState());
6!
113
      tasks.push(dispatch(saveUserSettings({ onboarding: { ...onboarding, showTips: show }, showHelptips: show })));
6✔
114
      tasks.push(dispatch({ type: SET_SHOW_HELP, show }));
6✔
115
    }
116
    return Promise.all(tasks);
14✔
117
  };
118

119
const setOnboardingProgress = value => dispatch => dispatch({ type: SET_ONBOARDING_PROGRESS, value });
187✔
120

121
export const setOnboardingDeviceType =
122
  (value, update = true) =>
187✔
123
  (dispatch, getState) => {
11✔
124
    let tasks = [dispatch({ type: SET_ONBOARDING_DEVICE_TYPE, value })];
11✔
125
    if (update) {
11✔
126
      const { onboarding = {} } = getUserSettings(getState());
3!
127
      tasks.push(dispatch(saveUserSettings({ onboarding: { ...onboarding, deviceType: value } })));
3✔
128
    }
129
    return Promise.all(tasks);
11✔
130
  };
131

132
export const setOnboardingApproach =
133
  (value, update = true) =>
187✔
134
  (dispatch, getState) => {
15✔
135
    let tasks = [dispatch({ type: SET_ONBOARDING_APPROACH, value })];
15✔
136
    if (update) {
15✔
137
      const { onboarding = {} } = getUserSettings(getState());
7!
138
      tasks.push(dispatch(saveUserSettings({ onboarding: { ...onboarding, approach: value } })));
7✔
139
    }
140
    return Promise.all(tasks);
15✔
141
  };
142

143
const setOnboardingArtifactIncluded = value => dispatch => dispatch({ type: SET_ONBOARDING_ARTIFACT_INCLUDED, value });
187✔
144

145
export const setShowCreateArtifactDialog = show => dispatch => dispatch({ type: SET_SHOW_CREATE_ARTIFACT, show });
187✔
146

147
export const setShowDismissOnboardingTipsDialog = show => dispatch => dispatch({ type: SET_SHOW_ONBOARDING_HELP_DIALOG, show });
187✔
148

149
export const setDemoArtifactPort = port => dispatch => dispatch({ type: SET_DEMO_ARTIFACT_PORT, value: port });
187✔
150

151
export const setOnboardingComplete = val => dispatch => {
187✔
152
  let tasks = [Promise.resolve(dispatch({ type: SET_ONBOARDING_COMPLETE, complete: val }))];
22✔
153
  if (val) {
22✔
154
    tasks.push(Promise.resolve(dispatch({ type: SET_SHOW_ONBOARDING_HELP, show: false })));
7✔
155
    tasks.push(Promise.resolve(dispatch(advanceOnboarding(onboardingStepNames.ONBOARDING_FINISHED))));
7✔
156
  }
157
  return Promise.all(tasks);
22✔
158
};
159

160
export const setOnboardingCanceled = () => dispatch =>
187✔
161
  Promise.all([
3✔
162
    Promise.resolve(dispatch(setShowOnboardingHelp(false))),
163
    Promise.resolve(dispatch(setShowDismissOnboardingTipsDialog(false))),
164
    Promise.resolve(dispatch({ type: SET_ONBOARDING_COMPLETE, complete: true }))
165
  ])
166
    // using ONBOARDING_FINISHED_NOTIFICATION to ensure we get the intended onboarding state set after
167
    // _advancing_ the onboarding progress
168
    .then(() => dispatch(advanceOnboarding(onboardingStepNames.ONBOARDING_FINISHED_NOTIFICATION)))
3✔
169
    // since we can't advance after ONBOARDING_CANCELED, track the step manually here
170
    .then(() => Tracking.event({ category: 'onboarding', action: onboardingSteps.ONBOARDING_CANCELED }));
3✔
171

172
const setOnboardingState = state => dispatch =>
187✔
173
  Promise.all([
8✔
174
    dispatch(setOnboardingComplete(state.complete)),
175
    dispatch(setOnboardingDeviceType(state.deviceType, false)),
176
    dispatch(setOnboardingApproach(state.approach, false)),
177
    dispatch(setOnboardingArtifactIncluded(state.artifactIncluded)),
178
    dispatch(setShowOnboardingHelp(state.showTips, false)),
179
    dispatch(setOnboardingProgress(state.progress)),
180
    dispatch(setShowCreateArtifactDialog(state.showArtifactCreation && !state.complete && state.showTips)),
8!
181
    dispatch(saveUserSettings({ onboarding: state }))
182
  ]);
183

184
export const advanceOnboarding = stepId => (dispatch, getState) => {
187✔
185
  const steps = Object.keys(onboardingSteps);
35✔
186
  const progress = steps.findIndex(step => step === getState().onboarding.progress);
897✔
187
  const stepIndex = steps.findIndex(step => step === stepId);
605✔
188
  // if there is no progress set yet, the onboarding state deduction hasn't happened
189
  // and the subsequent settings persistence would overwrite what we stored
190
  if (progress > stepIndex || getState().onboarding.progress === null) {
35✔
191
    return;
12✔
192
  }
193
  const madeProgress = steps[stepIndex + 1];
23✔
194
  const state = { ...getCurrentOnboardingState(getState()), progress: madeProgress };
23✔
195
  state.complete = stepIndex + 1 >= Object.keys(onboardingSteps).findIndex(step => step === onboardingStepNames.ONBOARDING_FINISHED) ? true : state.complete;
690✔
196
  Tracking.event({ category: 'onboarding', action: stepId });
23✔
197
  return Promise.all([dispatch(setOnboardingProgress(madeProgress)), dispatch(saveUserSettings({ onboarding: state }))]);
23✔
198
};
199

200
const determineProgress = (acceptedDevices, pendingDevices, releases, pastDeployments) => {
187✔
201
  const steps = Object.keys(onboardingSteps);
8✔
202
  let progress = -1;
8✔
203
  progress = pendingDevices.length > 1 ? steps.findIndex(step => step === onboardingStepNames.DEVICES_PENDING_ACCEPTING_ONBOARDING) : progress;
8!
204
  progress = acceptedDevices.length >= 1 ? steps.findIndex(step => step === onboardingStepNames.APPLICATION_UPDATE_REMINDER_TIP) : progress;
72!
205
  progress =
8✔
206
    acceptedDevices.length > 1 && releases.length > 1 ? steps.findIndex(step => step === onboardingStepNames.APPLICATION_UPDATE_REMINDER_TIP) : progress;
18✔
207
  progress =
8✔
208
    acceptedDevices.length > 1 && releases.length > 1 && pastDeployments.length > 1
26✔
209
      ? steps.findIndex(step => step === onboardingStepNames.DEPLOYMENTS_PAST_COMPLETED)
40✔
210
      : progress;
211
  progress =
8✔
212
    acceptedDevices.length >= 1 && releases.length >= 2 && pastDeployments.length > 1
26✔
213
      ? steps.findIndex(step => step === onboardingStepNames.ARTIFACT_MODIFIED_ONBOARDING)
58✔
214
      : progress;
215
  progress =
8✔
216
    acceptedDevices.length >= 1 && releases.length >= 2 && pastDeployments.length > 2
26!
217
      ? steps.findIndex(step => step === onboardingStepNames.ONBOARDING_FINISHED)
×
218
      : progress;
219
  return steps[progress];
8✔
220
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc