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

mendersoftware / gui / 897326496

pending completion
897326496

Pull #3752

gitlab-ci

mzedel
chore(e2e): made use of shared timeout & login checking values to remove code duplication

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3752: chore(e2e-tests): slightly simplified log in test + separated log out test

4395 of 6392 branches covered (68.76%)

8060 of 9780 relevant lines covered (82.41%)

126.17 hits per line

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

61.45
/src/js/components/common/dialogs/physicaldeviceonboarding.js
1
// Copyright 2019 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 React, { useEffect, useState } from 'react';
15
import { connect } from 'react-redux';
16
import { Link } from 'react-router-dom';
17

18
import { Help as HelpIcon, InfoOutlined as InfoIcon } from '@mui/icons-material';
19
import { Autocomplete, TextField } from '@mui/material';
20
import { createFilterOptions } from '@mui/material/useAutocomplete';
21

22
import { advanceOnboarding, setOnboardingApproach, setOnboardingDeviceType } from '../../../actions/onboardingActions';
23
import { EXTERNAL_PROVIDER } from '../../../constants/deviceConstants';
24
import { onboardingSteps } from '../../../constants/onboardingConstants';
25
import { getDebConfigurationCode, versionCompare } from '../../../helpers';
26
import { getDocsVersion, getIsEnterprise, getOnboardingState } from '../../../selectors';
27
import CopyCode from '../copy-code';
28
import { MenderTooltipClickable } from '../mendertooltip';
29

30
const filter = createFilterOptions();
4✔
31

32
const types = [
4✔
33
  { title: 'Raspberry Pi 3', value: 'raspberrypi3' },
34
  { title: 'Raspberry Pi 4', value: 'raspberrypi4' }
35
];
36

37
export const ConvertedImageNote = ({ docsVersion }) => (
4✔
38
  <p>
2✔
39
    We prepared an image, ready for Mender, for you to start with. You can find it in the{' '}
40
    <a href={`https://docs.mender.io/${docsVersion}get-started/preparation/prepare-a-raspberry-pi-device`} target="_blank" rel="noopener noreferrer">
41
      Prepare a Raspberry Pi device
42
    </a>{' '}
43
    documentation, which also contains instructions for initial device setup. Once you&apos;re done flashing you can go ahead and proceed to the next step.
44
  </p>
45
);
46

47
const IntegrationsLink = () => (
4✔
48
  <Link to="/settings/integrations" target="_blank">
×
49
    Integration settings
50
  </Link>
51
);
52

53
export const ExternalProviderTip = ({ hasExternalIntegration, integrationProvider }) => (
4✔
54
  <MenderTooltipClickable
5✔
55
    className="clickable flexbox muted"
56
    placement="bottom"
57
    style={{ alignItems: 'end', marginBottom: 3 }}
58
    title={
59
      <div style={{ maxWidth: 350 }}>
60
        {hasExternalIntegration ? (
5✔
61
          <p>
62
            Devices added here will be automatically integrated with the <i>{EXTERNAL_PROVIDER[integrationProvider].title}</i> you set in the{' '}
63
            <IntegrationsLink />.
64
          </p>
65
        ) : (
66
          <p>
67
            To connect your devices with <i>{EXTERNAL_PROVIDER[integrationProvider].title}</i>, go to <IntegrationsLink /> and set up the integration.
68
          </p>
69
        )}
70
      </div>
71
    }
72
  >
73
    <InfoIcon />
74
  </MenderTooltipClickable>
75
);
76

77
export const DeviceTypeTip = () => (
4✔
78
  <MenderTooltipClickable
2✔
79
    className="flexbox"
80
    placement="bottom"
81
    style={{ alignItems: 'end' }}
82
    title={
83
      <>
84
        <p>
85
          If you don&apos;t see your exact device on the list, choose <i>Generic ARMv6 or newer</i> to continue the tutorial for now.
86
        </p>
87
        <p>
88
          (Note: if your device is <i>not</i> based on ARMv6 or newer, the tutorial won&apos;t work - instead, go back and use the virtual device)
89
        </p>
90
      </>
91
    }
92
  >
93
    <div className="tooltip help" style={{ marginLeft: 0, position: 'initial' }}>
94
      <HelpIcon />
95
    </div>
96
  </MenderTooltipClickable>
97
);
98

99
export const DeviceTypeSelectionStep = ({
4✔
100
  docsVersion,
101
  hasConvertedImage,
102
  hasExternalIntegration,
103
  integrationProvider,
104
  onboardingState,
105
  onSelect,
106
  selection = '',
×
107
  version
108
}) => {
109
  const shouldShowOnboardingTip = !onboardingState.complete && onboardingState.showTips && onboardingState.showHelptips;
3✔
110
  const hasExternalIntegrationSupport = versionCompare(version, '3.2') > -1;
3✔
111
  return (
3✔
112
    <>
113
      <h4>Enter your device type</h4>
114
      <p>Setting this attribute on the device ensures that the device will only receive updates for compatible software releases.</p>
115

116
      <div style={{ display: 'grid', gridTemplateColumns: 'max-content 50px 150px', justifyItems: 'center' }}>
117
        <Autocomplete
118
          id="device-type-selection"
119
          autoSelect
120
          autoHighlight
121
          filterSelectedOptions
122
          freeSolo
123
          getOptionLabel={option => {
124
            // Value selected with enter, right from the input
125
            if (typeof option === 'string') {
9!
126
              return option;
9✔
127
            }
128
            if (option.key === 'custom' && option.value === selection) {
×
129
              return option.value;
×
130
            }
131
            return option.title;
×
132
          }}
133
          handleHomeEndKeys
134
          includeInputInList
135
          filterOptions={(options, params) => {
136
            const filtered = filter(options, params);
×
137
            if (filtered.length !== 1 && params.inputValue !== '') {
×
138
              filtered.push({
×
139
                value: params.inputValue,
140
                key: 'custom',
141
                title: `Use "${params.inputValue}"`
142
              });
143
            }
144
            return filtered;
×
145
          }}
146
          options={types}
147
          onChange={onSelect}
148
          renderInput={params => (
149
            <TextField {...params} label="Device type" placeholder="Choose a device type" InputProps={{ ...params.InputProps }} style={{ marginTop: 0 }} />
6✔
150
          )}
151
          style={{ maxWidth: 300 }}
152
          value={selection}
153
        />
154
        {shouldShowOnboardingTip ? <DeviceTypeTip /> : <div />}
3✔
155
        {hasExternalIntegrationSupport && <ExternalProviderTip hasExternalIntegration={hasExternalIntegration} integrationProvider={integrationProvider} />}
6✔
156
      </div>
157
      {hasConvertedImage && <ConvertedImageNote docsVersion={docsVersion} />}
4✔
158
    </>
159
  );
160
};
161

162
export const InstallationStep = ({ advanceOnboarding, selection, onboardingState, ...remainingProps }) => {
4✔
163
  const codeToCopy = getDebConfigurationCode({ ...remainingProps, deviceType: selection, isOnboarding: !onboardingState.complete });
1✔
164
  return (
1✔
165
    <>
166
      <h4>Log into your device and install the Mender client</h4>
167
      <p>
168
        Copy & paste and run this command <b>on your device</b>:
169
      </p>
170
      <CopyCode code={codeToCopy} onCopy={() => advanceOnboarding(onboardingSteps.DASHBOARD_ONBOARDING_START)} withDescription={true} />
×
171
      <p>This downloads the Mender client on the device, sets the configuration and starts the client.</p>
172
      <p>
173
        Once the client has started, your device will attempt to connect to the server. It will then appear in your Pending devices tab and you can continue.
174
      </p>
175
    </>
176
  );
177
};
178

179
const steps = {
4✔
180
  1: DeviceTypeSelectionStep,
181
  2: InstallationStep
182
};
183

184
export const PhysicalDeviceOnboarding = ({
4✔
185
  advanceOnboarding,
186
  docsVersion,
187
  hasExternalIntegration,
188
  integrationProvider,
189
  ipAddress,
190
  isHosted,
191
  isEnterprise,
192
  isDemoMode,
193
  isPreRelease,
194
  onboardingState,
195
  progress,
196
  setOnboardingApproach,
197
  setOnboardingDeviceType,
198
  tenantToken,
199
  version
200
}) => {
201
  const [selection, setSelection] = useState('');
2✔
202

203
  useEffect(() => {
2✔
204
    setOnboardingApproach('physical');
2✔
205
  }, []);
206

207
  const onSelect = (e, deviceType, reason) => {
2✔
208
    if (reason === 'selectOption') {
×
209
      setOnboardingDeviceType(deviceType.value);
×
210
      setSelection(deviceType.value);
×
211
    } else if (reason === 'clear') {
×
212
      setOnboardingDeviceType('');
×
213
      setSelection('');
×
214
    }
215
  };
216

217
  const hasConvertedImage = !!selection && selection.length && (selection.startsWith('raspberrypi3') || selection.startsWith('raspberrypi4'));
2!
218

219
  const ComponentToShow = steps[progress];
2✔
220
  return (
2✔
221
    <ComponentToShow
222
      advanceOnboarding={advanceOnboarding}
223
      hasExternalIntegration={hasExternalIntegration}
224
      docsVersion={docsVersion}
225
      hasConvertedImage={hasConvertedImage}
226
      integrationProvider={integrationProvider}
227
      ipAddress={ipAddress}
228
      isEnterprise={isEnterprise}
229
      isHosted={isHosted}
230
      isDemoMode={isDemoMode}
231
      isPreRelease={isPreRelease}
232
      onboardingState={onboardingState}
233
      onSelect={onSelect}
234
      selection={selection}
235
      tenantToken={tenantToken}
236
      version={version}
237
    />
238
  );
239
};
240

241
const actionCreators = { advanceOnboarding, setOnboardingApproach, setOnboardingDeviceType };
4✔
242

243
const mapStateToProps = state => {
4✔
244
  const integrationProvider = EXTERNAL_PROVIDER['iot-hub'].provider;
2✔
245
  const { credentials = {} } = state.organization.externalDeviceIntegrations.find(integration => integration.provider === integrationProvider) ?? {};
2✔
246
  const { [EXTERNAL_PROVIDER['iot-hub'].credentialsAttribute]: azureConnectionString = '' } = credentials;
2✔
247
  return {
2✔
248
    docsVersion: getDocsVersion(state),
249
    hasExternalIntegration: azureConnectionString,
250
    integrationProvider,
251
    ipAddress: state.app.hostAddress,
252
    isEnterprise: getIsEnterprise(state),
253
    isHosted: state.app.features.isHosted,
254
    isDemoMode: state.app.features.isDemoMode,
255
    isPreRelease: versionCompare(state.app.versionInformation.Integration, 'next') > -1,
256
    onboardingState: getOnboardingState(state),
257
    tenantToken: state.organization.organization.tenant_token,
258
    version: state.app.versionInformation.Integration
259
  };
260
};
261

262
export default connect(mapStateToProps, actionCreators)(PhysicalDeviceOnboarding);
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