• 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

94.29
/src/js/components/common/forms/passwordinput.js
1
// Copyright 2016 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, useRef, useState } from 'react';
15
import { Controller, useFormContext, useWatch } from 'react-hook-form';
16

17
import { CheckCircle as CheckIcon, Visibility as VisibilityIcon, VisibilityOff as VisibilityOffIcon } from '@mui/icons-material';
18
import { Button, FormControl, FormHelperText, IconButton, Input, InputAdornment, InputLabel } from '@mui/material';
19

20
import copy from 'copy-to-clipboard';
21
import generator from 'generate-password';
22

23
import { TIMEOUTS } from '../../../constants/appConstants';
24
import { toggle } from '../../../helpers';
25
import { runValidations } from './form';
26

27
const PasswordGenerateButtons = ({ clearPass, edit, generatePass }) => (
14✔
28
  <div className="pass-buttons">
63✔
29
    <Button color="primary" onClick={generatePass}>
30
      Generate
31
    </Button>
32
    {edit ? <Button onClick={clearPass}>Cancel</Button> : null}
63!
33
  </div>
34
);
35

36
const SCORE_THRESHOLD = 3;
14✔
37

38
const PasswordGenerationControls = ({ score, feedback }) => (
14✔
39
  <>
405✔
40
    <div className="help-text" id="pass-strength">
41
      Strength: <meter max={4} min={0} value={score} high={3.9} optimum={4} low={2.5} />
42
      {score > SCORE_THRESHOLD ? <CheckIcon className="fadeIn green" style={{ height: 18, marginTop: -3, marginBottom: -3 }} /> : null}
405✔
43
    </div>
44
    {!!feedback.length && (
507✔
45
      <p className="help-text">
46
        {feedback.map((message, index) => (
47
          <React.Fragment key={`feedback-${index}`}>
102✔
48
            <span>{message}</span>
49
            <br />
50
          </React.Fragment>
51
        ))}
52
      </p>
53
    )}
54
  </>
55
);
56

57
export const PasswordInput = ({
14✔
58
  autocomplete,
59
  className,
60
  control,
61
  create,
62
  defaultValue,
63
  disabled,
64
  edit,
65
  generate,
66
  id,
67
  InputLabelProps = {},
1,145✔
68
  label,
69
  onClear,
70
  placeholder,
71
  required,
72
  validations = ''
494✔
73
}) => {
74
  const [score, setScore] = useState('');
1,187✔
75
  const [visible, setVisible] = useState(false);
1,187✔
76
  const [copied, setCopied] = useState(false);
1,187✔
77
  const [feedback, setFeedback] = useState([]);
1,187✔
78
  const [confirmationId] = useState(id.includes('current') ? '' : ['password', 'password_confirmation'].find(thing => thing !== id));
2,119✔
79
  const timer = useRef();
1,187✔
80
  const {
81
    clearErrors,
82
    formState: { errors },
83
    setError,
84
    setValue,
85
    trigger,
86
    getValues
87
  } = useFormContext();
1,187✔
88
  const confirmation = useWatch({ name: confirmationId });
1,187✔
89
  const errorKey = `${id}-error`;
1,187✔
90

91
  useEffect(() => {
1,187✔
92
    return () => {
1,101✔
93
      clearTimeout(timer.current);
1,101✔
94
    };
95
  });
96

97
  const clearPassClick = () => {
1,187✔
98
    setValue(id, '');
×
99
    onClear();
×
100
    setCopied(false);
×
101
  };
102

103
  const generatePassClick = () => {
1,187✔
104
    const password = generator.generate({ length: 16, numbers: true });
5✔
105
    setValue(id, password);
5✔
106
    const form = getValues();
5✔
107
    if (form.hasOwnProperty(`${id}_confirmation`)) {
5✔
108
      setValue(`${id}_confirmation`, password);
1✔
109
    }
110
    copy(password);
5✔
111
    setCopied(true);
5✔
112
    setVisible(true);
5✔
113
    timer.current = setTimeout(() => setCopied(false), TIMEOUTS.fiveSeconds);
5✔
114
    trigger();
5✔
115
  };
116

117
  const validate = async (value = '') => {
1,187✔
118
    let { isValid, errortext } = runValidations({ id, required, validations, value });
308✔
119
    if (confirmation && value !== confirmation) {
308✔
120
      isValid = false;
60✔
121
      errortext = 'The passwords you provided do not match, please check again.';
60✔
122
    }
123
    if (isValid) {
308✔
124
      clearErrors(errorKey);
234✔
125
    } else {
126
      setError(errorKey, { type: 'validate', message: errortext });
74✔
127
    }
128
    if (!create || (!required && !value)) {
308✔
129
      return isValid;
193✔
130
    }
131
    const { default: zxcvbn } = await import(/* webpackChunkName: "zxcvbn" */ 'zxcvbn');
115✔
132
    const strength = zxcvbn(value);
115✔
133
    const score = strength.score;
115✔
134
    setFeedback(strength.feedback.suggestions || []);
115!
135
    setScore(score);
115✔
136
    return score > SCORE_THRESHOLD && isValid;
115✔
137
  };
138

139
  return (
1,187✔
140
    <div className={className}>
141
      <div className="password-wrapper">
142
        <Controller
143
          name={id}
144
          control={control}
145
          rules={{ required, validate }}
146
          render={({ field: { value, onChange, onBlur, ref }, fieldState: { error } }) => (
147
            <FormControl className={required ? 'required' : ''} error={Boolean(error?.message || errors[errorKey])} style={{ width: 400 }}>
1,460✔
148
              <InputLabel htmlFor={id} {...InputLabelProps}>
149
                {label}
150
              </InputLabel>
151
              <Input
152
                autoComplete={autocomplete}
153
                id={id}
154
                name={id}
155
                type={visible ? 'text' : 'password'}
1,460✔
156
                defaultValue={defaultValue}
157
                placeholder={placeholder}
158
                value={value ?? ''}
1,821✔
159
                disabled={disabled}
160
                inputRef={ref}
161
                required={required}
162
                onChange={({ target: { value } }) => {
163
                  setValue(id, value);
182✔
164
                  onChange(value);
182✔
165
                }}
166
                onBlur={onBlur}
167
                endAdornment={
168
                  <InputAdornment position="end">
169
                    <IconButton onClick={() => setVisible(toggle)} size="large">
×
170
                      {visible ? <VisibilityIcon /> : <VisibilityOffIcon />}
1,460✔
171
                    </IconButton>
172
                  </InputAdornment>
173
                }
174
              />
175
              <FormHelperText>{(errors[errorKey] || error)?.message}</FormHelperText>
2,758✔
176
            </FormControl>
177
          )}
178
        />
179
        {generate && !required && <PasswordGenerateButtons clearPass={clearPassClick} edit={edit} generatePass={generatePassClick} />}
1,293✔
180
      </div>
181
      {copied ? <div className="green fadeIn margin-bottom-small">Copied to clipboard</div> : null}
1,187✔
182
      {create && (
1,678✔
183
        <>
184
          <PasswordGenerationControls feedback={feedback} score={score} />
185
          {generate && required && <PasswordGenerateButtons clearPass={clearPassClick} edit={edit} generatePass={generatePassClick} />}
577✔
186
        </>
187
      )}
188
    </div>
189
  );
190
};
191

192
export default PasswordInput;
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