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

electron / fiddle / 16349153970

17 Jul 2025 03:21PM UTC coverage: 80.235% (-7.8%) from 87.992%
16349153970

push

github

web-flow
test: switch to Vitest (#1718)

* test: switch to Vitest

* chore: update code comment

Co-authored-by: Kevin Cui <158blackhole@gmail.com>

* test: make use of vi.useFakeTimers to improve test

---------

Co-authored-by: Kevin Cui <158blackhole@gmail.com>

1520 of 1645 branches covered (92.4%)

Branch coverage included in aggregate %.

15 of 16 new or added lines in 12 files covered. (93.75%)

504 existing lines in 45 files now uncovered.

8807 of 11226 relevant lines covered (78.45%)

32.71 hits per line

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

97.54
/src/renderer/components/version-select.tsx
1
import * as React from 'react';
1✔
2

3
import {
1✔
4
  Button,
5
  ButtonGroupProps,
6
  ContextMenu,
7
  IconName,
8
  Intent,
9
  Menu,
10
  MenuItem,
11
} from '@blueprintjs/core';
12
import { Tooltip2 } from '@blueprintjs/popover2';
1✔
13
import {
1✔
14
  ItemListPredicate,
15
  ItemListRenderer,
16
  ItemRenderer,
17
  Select,
18
} from '@blueprintjs/select';
19
import { observer } from 'mobx-react';
1✔
20
import { FixedSizeList, ListChildComponentProps } from 'react-window';
1✔
21
import semver from 'semver';
1✔
22

23
import { InstallState, RunnableVersion, VersionSource } from '../../interfaces';
1✔
24
import { AppState } from '../state';
25
import { disableDownload } from '../utils/disable-download';
1✔
26
import { highlightText } from '../utils/highlight-text';
1✔
27

28
const ElectronVersionSelect = Select.ofType<RunnableVersion>();
1✔
29

30
const FixedSizeListItem = ({ index, data, style }: ListChildComponentProps) => {
1✔
31
  const { filteredItems, renderItem } = data;
35✔
32
  const renderedItem = renderItem(filteredItems[index], index);
35✔
33

34
  return <div style={style}>{renderedItem}</div>;
35✔
35
};
35✔
36

37
const itemListRenderer: ItemListRenderer<RunnableVersion> = ({
1✔
38
  filteredItems,
4✔
39
  renderItem,
4✔
40
  itemsParentRef,
4✔
41
}) => {
4✔
42
  const InnerElement = React.forwardRef((props, ref: React.Ref<Menu>) => {
4✔
43
    return <Menu ref={ref} ulRef={itemsParentRef} {...props} />;
5✔
44
  });
4✔
45
  InnerElement.displayName = 'Menu';
4✔
46

47
  return (
4✔
48
    <FixedSizeList
4✔
49
      innerElementType={InnerElement}
4✔
50
      height={300}
4✔
51
      width={400}
4✔
52
      itemCount={filteredItems.length}
4✔
53
      itemSize={30}
4✔
54
      itemData={{ renderItem, filteredItems }}
4✔
55
    >
56
      {FixedSizeListItem}
4✔
57
    </FixedSizeList>
4✔
58
  );
59
};
4✔
60

61
/**
62
 * Helper method: Returns the <Select /> label for an Electron
63
 * version.
64
 */
65
export function getItemLabel({ source, state, name }: RunnableVersion): string {
1✔
66
  // If a version is local, either it's there or it's not.
67
  if (source === VersionSource.local) {
43✔
68
    return state === InstallState.missing ? 'Unavailable' : name || 'Local';
3✔
69
  }
3✔
70

71
  const installStateLabels: Record<InstallState, string> = {
40✔
72
    missing: 'Not Downloaded',
40✔
73
    downloading: 'Downloading',
40✔
74
    downloaded: 'Downloaded',
40✔
75
    installing: 'Downloaded',
40✔
76
    installed: 'Downloaded',
40✔
77
  } as const;
40✔
78
  return installStateLabels[state] || '';
43!
79
}
43✔
80

81
/**
82
 * Helper method: Returns the <Select /> icon for an Electron
83
 * version.
84
 */
85
export function getItemIcon({ source, state }: RunnableVersion): IconName {
1✔
86
  // If a version is local, either it's there or it's not.
87
  if (source === VersionSource.local) {
43!
88
    return state === InstallState.missing ? 'issue' : 'saved';
×
UNCOV
89
  }
×
90

91
  const installStateIcons: Record<InstallState, IconName> = {
43✔
92
    missing: 'cloud',
43✔
93
    downloading: 'cloud-download',
43✔
94
    downloaded: 'compressed',
43✔
95
    installing: 'compressed',
43✔
96
    installed: 'saved',
43✔
97
  } as const;
43✔
98

99
  return installStateIcons[state] || '';
43!
100
}
43✔
101

102
/**
103
 * Helper method: Returns the <Select /> predicate for an Electron
104
 * version.
105
 *
106
 * Sorts by index of the chosen query.
107
 * For example, if we take the following versions:
108
 * [3.0.0, 14.3.0, 13.2.0, 12.0.0-nightly.20210301, 12.0.0-beta.3]
109
 * and a search query of '3', this method would sort them into:
110
 * [3.0.0, 13.2.0, 14.3.0, 12.0.0-beta.3, 12.0.0-nightly.20210301]
111
 */
112
export const filterItems: ItemListPredicate<RunnableVersion> = (
1✔
113
  query,
4✔
114
  versions,
4✔
115
) => {
4✔
116
  if (query === '') return versions;
4✔
117

118
  const q = query.toLowerCase();
2✔
119

120
  return versions
2✔
121
    .map((version: RunnableVersion) => {
2✔
122
      const lowercase = version.version.toLowerCase();
14✔
123
      return {
14✔
124
        index: lowercase.indexOf(q),
14✔
125
        coerced: semver.coerce(lowercase),
14✔
126
        version,
14✔
127
      };
14✔
128
    })
2✔
129
    .filter((item) => item.index !== -1)
2✔
130
    .sort((a, b) => {
2✔
131
      // If the user is searching for e.g. 'nightly' we
132
      // want to sort nightlies by descending major version.
133
      if (isNaN(+q)) {
15✔
134
        if (a.coerced && b.coerced) {
7✔
135
          return semver.rcompare(a.coerced, b.coerced);
7✔
136
        }
7✔
137
      }
7✔
138
      return a.index - b.index;
8✔
139
    })
2✔
140
    .map((item) => item.version);
2✔
141
};
2✔
142

143
/**
144
 * Renders a context menu to copy the current Electron version.
145
 *
146
 * @param version - the Electron version number to copy.
147
 */
148
export const renderVersionContextMenu = (
1✔
149
  e: React.MouseEvent<HTMLButtonElement>,
1✔
150
  version: string,
1✔
151
) => {
1✔
152
  e.preventDefault();
1✔
153

154
  ContextMenu.show(
1✔
155
    <Menu>
1✔
156
      <MenuItem
1✔
157
        text="Copy Version Number"
1✔
158
        onClick={() => {
1✔
159
          navigator.clipboard.writeText(version);
1✔
160
        }}
1✔
161
      />
1✔
162
    </Menu>,
1✔
163
    { left: e.clientX, top: e.clientY },
1✔
164
  );
1✔
165
};
1✔
166

167
/**
168
 * Helper method: Returns the <Select /> <MenuItem /> for Electron
169
 * versions.
170
 */
171
export const renderItem: ItemRenderer<RunnableVersion> = (
1✔
172
  item,
38✔
173
  { handleClick, modifiers, query },
38✔
174
) => {
38✔
175
  if (!modifiers.matchesPredicate) {
38✔
176
    return null;
1✔
177
  }
1✔
178

179
  if (disableDownload(item.version)) {
38✔
180
    return (
1✔
181
      <Tooltip2
1✔
182
        className="disabled-menu-tooltip"
1✔
183
        modifiers={{
1✔
184
          flip: { enabled: false },
1✔
185
          preventOverflow: { enabled: false },
1✔
186
          hide: { enabled: false },
1✔
187
        }}
1✔
188
        position="bottom"
1✔
189
        intent={Intent.PRIMARY}
1✔
190
        content={`Version is not available on current OS`}
1✔
191
      >
192
        <MenuItem
1✔
193
          active={modifiers.active}
1✔
194
          data-testid="disabled-menu-item"
1✔
195
          disabled={true}
1✔
196
          text={highlightText(item.version, query)}
1✔
197
          key={item.version}
1✔
198
          label={getItemLabel(item)}
1✔
199
          icon={getItemIcon(item)}
1✔
200
        />
1✔
201
      </Tooltip2>
1✔
202
    );
203
  }
1✔
204

205
  return (
36✔
206
    <MenuItem
36✔
207
      active={modifiers.active}
36✔
208
      disabled={modifiers.disabled}
36✔
209
      text={highlightText(item.version, query)}
36✔
210
      key={item.version}
36✔
211
      onClick={handleClick}
36✔
212
      label={getItemLabel(item)}
36✔
213
      icon={getItemIcon(item)}
36✔
214
    />
36✔
215
  );
216
};
36✔
217

218
interface VersionSelectState {
219
  value: string;
220
}
221

222
interface VersionSelectProps {
223
  appState: AppState;
224
  disabled?: boolean;
225
  currentVersion: RunnableVersion;
226
  onVersionSelect: (version: RunnableVersion) => void;
227
  buttonGroupProps?: ButtonGroupProps;
228
  itemDisabled?:
229
    | keyof RunnableVersion
230
    | ((item: RunnableVersion, index: number) => boolean);
231
}
232

233
/**
234
 * A dropdown allowing the selection of Electron versions. The actual
235
 * download is managed in the state.
236
 */
237
export const VersionSelect = observer(
1✔
238
  class VersionSelect extends React.Component<
1✔
239
    VersionSelectProps,
240
    VersionSelectState
241
  > {
1✔
242
    public render() {
1✔
243
      const { currentVersion, itemDisabled } = this.props;
2✔
244
      const { version } = currentVersion;
2✔
245

246
      return (
2✔
247
        <ElectronVersionSelect
2✔
248
          filterable={true}
2✔
249
          items={this.props.appState.versionsToShow}
2✔
250
          itemRenderer={renderItem}
2✔
251
          itemListPredicate={filterItems}
2✔
252
          itemListRenderer={itemListRenderer}
2✔
253
          itemDisabled={itemDisabled}
2✔
254
          onItemSelect={this.props.onVersionSelect}
2✔
255
          noResults={<MenuItem disabled={true} text="No results." />}
2✔
256
          disabled={!!this.props.disabled}
2✔
257
        >
258
          <Button
2✔
259
            id="version-chooser"
2✔
260
            text={version}
2✔
261
            icon={getItemIcon(currentVersion)}
2✔
262
            onContextMenu={(e: React.MouseEvent<HTMLButtonElement>) => {
2✔
263
              renderVersionContextMenu(e, version);
1✔
264
            }}
1✔
265
            disabled={!!this.props.disabled}
2✔
266
          />
2✔
267
        </ElectronVersionSelect>
2✔
268
      );
269
    }
2✔
270
  },
1✔
271
);
1✔
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

© 2026 Coveralls, Inc