storybook_vitest_addon 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Panel.js +96 -0
- package/dist/cjs/__tests__/Panel.test.js +132 -0
- package/dist/cjs/__tests__/fixtures.js +55 -0
- package/dist/cjs/__tests__/setup.js +3 -0
- package/dist/cjs/__tests__/utils.test.js +113 -0
- package/dist/cjs/constants.js +9 -0
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/preset/manager.js +24 -0
- package/dist/cjs/preset/preview.js +7 -0
- package/dist/cjs/typings.d.js +5 -0
- package/dist/esm/Panel.js +87 -0
- package/dist/esm/__tests__/Panel.test.js +129 -0
- package/dist/esm/__tests__/fixtures.js +49 -0
- package/dist/esm/__tests__/setup.js +1 -0
- package/dist/esm/__tests__/utils.test.js +111 -0
- package/dist/esm/constants.js +3 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/preset/manager.js +21 -0
- package/dist/esm/preset/preview.js +1 -0
- package/dist/esm/typings.d.js +1 -0
- package/dist/ts/Panel.d.ts +6 -0
- package/dist/ts/__tests__/Panel.test.d.ts +1 -0
- package/dist/ts/__tests__/fixtures.d.ts +3 -0
- package/dist/ts/__tests__/setup.d.ts +1 -0
- package/dist/ts/__tests__/utils.test.d.ts +1 -0
- package/dist/ts/constants.d.ts +3 -0
- package/dist/ts/index.d.ts +2 -0
- package/dist/ts/preset/preview.d.ts +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports["default"] = void 0;
|
|
7
|
+
exports.extractFileTestsData = extractFileTestsData;
|
|
8
|
+
exports.reduceFileTestResults = reduceFileTestResults;
|
|
9
|
+
var _react = _interopRequireDefault(require("react"));
|
|
10
|
+
var _constants = require("./constants");
|
|
11
|
+
var _managerApi = require("storybook/manager-api");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
13
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
14
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
15
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
16
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
17
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
18
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
19
|
+
function reduceFileTestResults(accumulator, assertionResult) {
|
|
20
|
+
var _assertionResult$ance = _slicedToArray(assertionResult.ancestorTitles, 2),
|
|
21
|
+
testGroupName = _assertionResult$ance[1];
|
|
22
|
+
if (!accumulator[testGroupName]) {
|
|
23
|
+
accumulator[testGroupName] = [];
|
|
24
|
+
}
|
|
25
|
+
accumulator[testGroupName].push({
|
|
26
|
+
title: assertionResult.title,
|
|
27
|
+
status: assertionResult.status
|
|
28
|
+
});
|
|
29
|
+
return accumulator;
|
|
30
|
+
}
|
|
31
|
+
function extractFileTestsData(results, fileName) {
|
|
32
|
+
var _results$testResults;
|
|
33
|
+
var fileTestResults = (_results$testResults = results.testResults) === null || _results$testResults === void 0 ? void 0 : _results$testResults.find(function (r) {
|
|
34
|
+
return r.name.includes(fileName);
|
|
35
|
+
});
|
|
36
|
+
if (!fileTestResults) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
return fileTestResults.assertionResults.reduce(reduceFileTestResults, {});
|
|
40
|
+
}
|
|
41
|
+
var VitestPanel = function VitestPanel() {
|
|
42
|
+
var params = (0, _managerApi.useParameter)(_constants.PARAM_KEY);
|
|
43
|
+
if (!params) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
var testResults = params.testResults,
|
|
47
|
+
fileName = params.testFile;
|
|
48
|
+
var fileTestResults = null;
|
|
49
|
+
if (testResults && fileName) {
|
|
50
|
+
fileTestResults = extractFileTestsData(testResults, fileName);
|
|
51
|
+
}
|
|
52
|
+
var error = null;
|
|
53
|
+
if (!fileName && !testResults) {
|
|
54
|
+
error = 'Please check your config: missing both `testFile` and `testResults`.{" "}';
|
|
55
|
+
} else if (!fileName) {
|
|
56
|
+
error = "Please check your config: missing `testFile` name.";
|
|
57
|
+
} else if (!testResults) {
|
|
58
|
+
error = "Please check your config: missing `testResults` file.";
|
|
59
|
+
} else if (!("testResults" in testResults)) {
|
|
60
|
+
error = "Please check your config: `testResults` file does not contain valid results format.";
|
|
61
|
+
} else if (!fileTestResults || Object.keys(fileTestResults).length === 0) {
|
|
62
|
+
error = "No tests found.";
|
|
63
|
+
}
|
|
64
|
+
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
65
|
+
style: {
|
|
66
|
+
padding: "1rem"
|
|
67
|
+
}
|
|
68
|
+
}, error && /*#__PURE__*/_react["default"].createElement("p", null, " ", error), fileTestResults && Object.entries(fileTestResults).map(function (_ref) {
|
|
69
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
70
|
+
title = _ref2[0],
|
|
71
|
+
group = _ref2[1];
|
|
72
|
+
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
73
|
+
key: title
|
|
74
|
+
}, /*#__PURE__*/_react["default"].createElement("strong", null, title), /*#__PURE__*/_react["default"].createElement("div", {
|
|
75
|
+
style: {
|
|
76
|
+
display: "flex",
|
|
77
|
+
flexDirection: "column",
|
|
78
|
+
rowGap: 8,
|
|
79
|
+
paddingTop: 8,
|
|
80
|
+
paddingBottom: 16
|
|
81
|
+
}
|
|
82
|
+
}, group.map(function (d) {
|
|
83
|
+
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
84
|
+
key: d.title,
|
|
85
|
+
style: {
|
|
86
|
+
display: "flex",
|
|
87
|
+
flexDirection: "row",
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
columnGap: 4,
|
|
90
|
+
paddingLeft: 16
|
|
91
|
+
}
|
|
92
|
+
}, /*#__PURE__*/_react["default"].createElement("div", null, d.status === "passed" ? "✔️" : "❌"), /*#__PURE__*/_react["default"].createElement("div", null, d.title));
|
|
93
|
+
})));
|
|
94
|
+
}));
|
|
95
|
+
};
|
|
96
|
+
var _default = exports["default"] = VitestPanel;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _vitest = require("vitest");
|
|
6
|
+
var _Panel = _interopRequireDefault(require("../Panel"));
|
|
7
|
+
var _fixtures = require("./fixtures");
|
|
8
|
+
var _managerApi = require("storybook/manager-api");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
10
|
+
_vitest.vi.mock("storybook/manager-api", function () {
|
|
11
|
+
return {
|
|
12
|
+
useParameter: _vitest.vi.fn()
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
_vitest.vi.mock("../constants", function () {
|
|
16
|
+
return {
|
|
17
|
+
PARAM_KEY: "vitest"
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
var mockUseParameter = _vitest.vi.mocked(_managerApi.useParameter);
|
|
21
|
+
(0, _vitest.describe)("VitestPanel", function () {
|
|
22
|
+
(0, _vitest.beforeEach)(function () {
|
|
23
|
+
_vitest.vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
(0, _vitest.describe)("when useParameter returns a falsy value", function () {
|
|
26
|
+
(0, _vitest.it)("renders nothing when params are null", function () {
|
|
27
|
+
mockUseParameter.mockReturnValue(null);
|
|
28
|
+
var _render = (0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null)),
|
|
29
|
+
container = _render.container;
|
|
30
|
+
(0, _vitest.expect)(container.firstChild).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
(0, _vitest.it)("renders nothing when params are undefined", function () {
|
|
33
|
+
mockUseParameter.mockReturnValue(undefined);
|
|
34
|
+
var _render2 = (0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null)),
|
|
35
|
+
container = _render2.container;
|
|
36
|
+
(0, _vitest.expect)(container.firstChild).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
(0, _vitest.describe)("error states", function () {
|
|
40
|
+
(0, _vitest.it)("shows error when both testFile and testResults are missing", function () {
|
|
41
|
+
mockUseParameter.mockReturnValue({});
|
|
42
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
43
|
+
(0, _vitest.expect)(_react2.screen.getByText(/missing both `testFile` and `testResults`/)).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
(0, _vitest.it)("shows error when testFile is missing but testResults is present", function () {
|
|
46
|
+
mockUseParameter.mockReturnValue({
|
|
47
|
+
testResults: _fixtures.sampleTestResults
|
|
48
|
+
});
|
|
49
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
50
|
+
(0, _vitest.expect)(_react2.screen.getByText(/missing `testFile` name/)).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
(0, _vitest.it)("shows error when testResults is missing but testFile is present", function () {
|
|
53
|
+
mockUseParameter.mockReturnValue({
|
|
54
|
+
testFile: "Button.test.tsx"
|
|
55
|
+
});
|
|
56
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
57
|
+
(0, _vitest.expect)(_react2.screen.getByText(/missing `testResults` file/)).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
(0, _vitest.it)("shows error when testResults object lacks the testResults property", function () {
|
|
60
|
+
mockUseParameter.mockReturnValue({
|
|
61
|
+
testFile: "Button.test.tsx",
|
|
62
|
+
testResults: {
|
|
63
|
+
success: true
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
67
|
+
(0, _vitest.expect)(_react2.screen.getByText(/does not contain valid results format/)).toBeInTheDocument();
|
|
68
|
+
});
|
|
69
|
+
(0, _vitest.it)("shows 'No tests found' when testFile does not match any result", function () {
|
|
70
|
+
mockUseParameter.mockReturnValue({
|
|
71
|
+
testFile: "NonExistent.test.tsx",
|
|
72
|
+
testResults: _fixtures.sampleTestResults
|
|
73
|
+
});
|
|
74
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
75
|
+
(0, _vitest.expect)(_react2.screen.getByText(/No tests found/)).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
(0, _vitest.describe)("successful rendering", function () {
|
|
79
|
+
(0, _vitest.beforeEach)(function () {
|
|
80
|
+
mockUseParameter.mockReturnValue({
|
|
81
|
+
testFile: "Button.test.tsx",
|
|
82
|
+
testResults: _fixtures.sampleTestResults
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
(0, _vitest.it)("renders no error message", function () {
|
|
86
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
87
|
+
(0, _vitest.expect)(_react2.screen.queryByText(/Please check your config/)).toBeNull();
|
|
88
|
+
(0, _vitest.expect)(_react2.screen.queryByText(/No tests found/)).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
(0, _vitest.it)("renders each test group as a bold heading", function () {
|
|
91
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
92
|
+
var headings = _react2.screen.getAllByText(/Button unit tests|Button accessibility/);
|
|
93
|
+
headings.forEach(function (el) {
|
|
94
|
+
return (0, _vitest.expect)(el.tagName).toBe("STRONG");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
(0, _vitest.it)("renders all test titles", function () {
|
|
98
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
99
|
+
(0, _vitest.expect)(_react2.screen.getByText("renders text and children")).toBeInTheDocument();
|
|
100
|
+
(0, _vitest.expect)(_react2.screen.getByText("handles click action")).toBeInTheDocument();
|
|
101
|
+
(0, _vitest.expect)(_react2.screen.getByText("has correct aria label")).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
(0, _vitest.it)("shows ✔️ for passed tests", function () {
|
|
104
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
105
|
+
var passIcons = _react2.screen.getAllByText("✔️");
|
|
106
|
+
(0, _vitest.expect)(passIcons).toHaveLength(2);
|
|
107
|
+
});
|
|
108
|
+
(0, _vitest.it)("shows ❌ for failed tests", function () {
|
|
109
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
110
|
+
var failIcons = _react2.screen.getAllByText("❌");
|
|
111
|
+
(0, _vitest.expect)(failIcons).toHaveLength(1);
|
|
112
|
+
});
|
|
113
|
+
(0, _vitest.it)("renders the correct number of test groups", function () {
|
|
114
|
+
(0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
115
|
+
(0, _vitest.expect)(_react2.screen.getByText("Button unit tests")).toBeInTheDocument();
|
|
116
|
+
(0, _vitest.expect)(_react2.screen.getByText("Button accessibility")).toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
(0, _vitest.describe)("layout and container", function () {
|
|
120
|
+
(0, _vitest.it)("wraps content in a padded div", function () {
|
|
121
|
+
mockUseParameter.mockReturnValue({
|
|
122
|
+
testFile: "Button.test.tsx",
|
|
123
|
+
testResults: _fixtures.sampleTestResults
|
|
124
|
+
});
|
|
125
|
+
var _render3 = (0, _react2.render)(/*#__PURE__*/_react["default"].createElement(_Panel["default"], null)),
|
|
126
|
+
container = _render3.container;
|
|
127
|
+
var wrapper = container.firstChild;
|
|
128
|
+
(0, _vitest.expect)(wrapper.tagName).toBe("DIV");
|
|
129
|
+
(0, _vitest.expect)(wrapper.style.padding).toBe("1rem");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.sampleTestResults = exports.makeAssertion = void 0;
|
|
7
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
8
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
9
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
10
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
11
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
12
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
13
|
+
var makeAssertion = exports.makeAssertion = function makeAssertion() {
|
|
14
|
+
var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
15
|
+
return _objectSpread({
|
|
16
|
+
ancestorTitles: ["", "My Suite"],
|
|
17
|
+
fullName: "My Suite renders correctly",
|
|
18
|
+
title: "renders correctly",
|
|
19
|
+
duration: 10,
|
|
20
|
+
status: "passed"
|
|
21
|
+
}, overrides);
|
|
22
|
+
};
|
|
23
|
+
var sampleTestResults = exports.sampleTestResults = {
|
|
24
|
+
numTotalTestSuites: 1,
|
|
25
|
+
numPassedTestSuites: 1,
|
|
26
|
+
numFailedTestSuites: 0,
|
|
27
|
+
numPendingTestSuites: 0,
|
|
28
|
+
numTotalTests: 3,
|
|
29
|
+
numPassedTests: 2,
|
|
30
|
+
numFailedTests: 1,
|
|
31
|
+
numPendingTests: 0,
|
|
32
|
+
numTodoTests: 0,
|
|
33
|
+
startTime: 1698956313163,
|
|
34
|
+
success: true,
|
|
35
|
+
testResults: [{
|
|
36
|
+
assertionResults: [makeAssertion({
|
|
37
|
+
ancestorTitles: ["", "Button unit tests"],
|
|
38
|
+
title: "renders text and children",
|
|
39
|
+
status: "passed"
|
|
40
|
+
}), makeAssertion({
|
|
41
|
+
ancestorTitles: ["", "Button unit tests"],
|
|
42
|
+
title: "handles click action",
|
|
43
|
+
status: "passed"
|
|
44
|
+
}), makeAssertion({
|
|
45
|
+
ancestorTitles: ["", "Button accessibility"],
|
|
46
|
+
title: "has correct aria label",
|
|
47
|
+
status: "failed"
|
|
48
|
+
})],
|
|
49
|
+
startTime: 1698956314807,
|
|
50
|
+
endTime: 1698956314843,
|
|
51
|
+
status: "passed",
|
|
52
|
+
message: "",
|
|
53
|
+
name: "/path/to/src/components/Button/Button.test.tsx"
|
|
54
|
+
}]
|
|
55
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _vitest = require("vitest");
|
|
4
|
+
var _Panel = require("../Panel");
|
|
5
|
+
var _fixtures = require("./fixtures");
|
|
6
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
7
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
8
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
10
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
11
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
12
|
+
(0, _vitest.describe)("reduceFileTestResults", function () {
|
|
13
|
+
(0, _vitest.it)("creates a new group for an unseen ancestorTitle", function () {
|
|
14
|
+
var result = (0, _Panel.reduceFileTestResults)({}, (0, _fixtures.makeAssertion)());
|
|
15
|
+
(0, _vitest.expect)(result).toEqual({
|
|
16
|
+
"My Suite": [{
|
|
17
|
+
title: "renders correctly",
|
|
18
|
+
status: "passed"
|
|
19
|
+
}]
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
(0, _vitest.it)("appends to an existing group for the same ancestorTitle", function () {
|
|
23
|
+
var initial = {
|
|
24
|
+
"My Suite": [{
|
|
25
|
+
title: "renders correctly",
|
|
26
|
+
status: "passed"
|
|
27
|
+
}]
|
|
28
|
+
};
|
|
29
|
+
var result = (0, _Panel.reduceFileTestResults)(initial, (0, _fixtures.makeAssertion)({
|
|
30
|
+
title: "handles click",
|
|
31
|
+
status: "failed"
|
|
32
|
+
}));
|
|
33
|
+
(0, _vitest.expect)(result["My Suite"]).toHaveLength(2);
|
|
34
|
+
(0, _vitest.expect)(result["My Suite"][1]).toEqual({
|
|
35
|
+
title: "handles click",
|
|
36
|
+
status: "failed"
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
(0, _vitest.it)("handles multiple distinct groups without mixing entries", function () {
|
|
40
|
+
var assertions = [(0, _fixtures.makeAssertion)({
|
|
41
|
+
ancestorTitles: ["", "Group A"],
|
|
42
|
+
title: "test 1"
|
|
43
|
+
}), (0, _fixtures.makeAssertion)({
|
|
44
|
+
ancestorTitles: ["", "Group B"],
|
|
45
|
+
title: "test 2"
|
|
46
|
+
}), (0, _fixtures.makeAssertion)({
|
|
47
|
+
ancestorTitles: ["", "Group A"],
|
|
48
|
+
title: "test 3"
|
|
49
|
+
})];
|
|
50
|
+
var result = assertions.reduce(_Panel.reduceFileTestResults, {});
|
|
51
|
+
(0, _vitest.expect)(Object.keys(result)).toEqual(["Group A", "Group B"]);
|
|
52
|
+
(0, _vitest.expect)(result["Group A"]).toHaveLength(2);
|
|
53
|
+
(0, _vitest.expect)(result["Group B"]).toHaveLength(1);
|
|
54
|
+
});
|
|
55
|
+
(0, _vitest.it)("preserves the status value from each assertion", function () {
|
|
56
|
+
var result = (0, _Panel.reduceFileTestResults)({}, (0, _fixtures.makeAssertion)({
|
|
57
|
+
status: "failed"
|
|
58
|
+
}));
|
|
59
|
+
(0, _vitest.expect)(result["My Suite"][0].status).toBe("failed");
|
|
60
|
+
});
|
|
61
|
+
(0, _vitest.it)("only stores title and status, discarding other assertion fields", function () {
|
|
62
|
+
var result = (0, _Panel.reduceFileTestResults)({}, (0, _fixtures.makeAssertion)());
|
|
63
|
+
var entry = result["My Suite"][0];
|
|
64
|
+
(0, _vitest.expect)(Object.keys(entry)).toEqual(["title", "status"]);
|
|
65
|
+
});
|
|
66
|
+
(0, _vitest.it)("uses the second element of ancestorTitles as the group key", function () {
|
|
67
|
+
var assertion = (0, _fixtures.makeAssertion)({
|
|
68
|
+
ancestorTitles: ["ignored-parent", "actual-group"]
|
|
69
|
+
});
|
|
70
|
+
var result = (0, _Panel.reduceFileTestResults)({}, assertion);
|
|
71
|
+
(0, _vitest.expect)(result["actual-group"]).toBeDefined();
|
|
72
|
+
(0, _vitest.expect)(result["ignored-parent"]).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
(0, _vitest.describe)("extractFileTestsData", function () {
|
|
76
|
+
(0, _vitest.it)("returns an empty object when no file matches", function () {
|
|
77
|
+
var result = (0, _Panel.extractFileTestsData)(_fixtures.sampleTestResults, "NonExistent.test.tsx");
|
|
78
|
+
(0, _vitest.expect)(result).toEqual({});
|
|
79
|
+
});
|
|
80
|
+
(0, _vitest.it)("returns grouped results when the file name matches exactly", function () {
|
|
81
|
+
var result = (0, _Panel.extractFileTestsData)(_fixtures.sampleTestResults, "Button.test.tsx");
|
|
82
|
+
(0, _vitest.expect)(result).toHaveProperty("Button unit tests");
|
|
83
|
+
(0, _vitest.expect)(result["Button unit tests"]).toHaveLength(2);
|
|
84
|
+
});
|
|
85
|
+
(0, _vitest.it)("matches by partial file name using includes", function () {
|
|
86
|
+
var result = (0, _Panel.extractFileTestsData)(_fixtures.sampleTestResults, "Button");
|
|
87
|
+
(0, _vitest.expect)(result).toHaveProperty("Button unit tests");
|
|
88
|
+
});
|
|
89
|
+
(0, _vitest.it)("groups assertion results under their respective suite names", function () {
|
|
90
|
+
var result = (0, _Panel.extractFileTestsData)(_fixtures.sampleTestResults, "Button.test.tsx");
|
|
91
|
+
(0, _vitest.expect)(Object.keys(result)).toContain("Button unit tests");
|
|
92
|
+
(0, _vitest.expect)(Object.keys(result)).toContain("Button accessibility");
|
|
93
|
+
});
|
|
94
|
+
(0, _vitest.it)("returns an empty object when testResults array is empty", function () {
|
|
95
|
+
var emptyResults = _objectSpread(_objectSpread({}, _fixtures.sampleTestResults), {}, {
|
|
96
|
+
testResults: []
|
|
97
|
+
});
|
|
98
|
+
var result = (0, _Panel.extractFileTestsData)(emptyResults, "Button.test.tsx");
|
|
99
|
+
(0, _vitest.expect)(result).toEqual({});
|
|
100
|
+
});
|
|
101
|
+
(0, _vitest.it)("handles testResults being undefined gracefully", function () {
|
|
102
|
+
var malformed = {};
|
|
103
|
+
var result = (0, _Panel.extractFileTestsData)(malformed, "Button.test.tsx");
|
|
104
|
+
(0, _vitest.expect)(result).toEqual({});
|
|
105
|
+
});
|
|
106
|
+
(0, _vitest.it)("returns full grouped structure for all assertion entries in the file", function () {
|
|
107
|
+
var result = (0, _Panel.extractFileTestsData)(_fixtures.sampleTestResults, "Button.test.tsx");
|
|
108
|
+
var passedGroup = result["Button unit tests"];
|
|
109
|
+
(0, _vitest.expect)(passedGroup.map(function (r) {
|
|
110
|
+
return r.title;
|
|
111
|
+
})).toEqual(["renders text and children", "handles click action"]);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PARAM_KEY = exports.PANEL_ID = exports.ADDON_ID = void 0;
|
|
7
|
+
var ADDON_ID = exports.ADDON_ID = "storybook/vitest";
|
|
8
|
+
var PANEL_ID = exports.PANEL_ID = "".concat(ADDON_ID, "/panel");
|
|
9
|
+
var PARAM_KEY = exports.PARAM_KEY = "vitest";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports["default"] = void 0;
|
|
7
|
+
// if (module && module.hot && module.hot.decline) {
|
|
8
|
+
// module.hot.decline();
|
|
9
|
+
// }
|
|
10
|
+
// make it work with --isolatedModules
|
|
11
|
+
var _default = exports["default"] = {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _components = require("storybook/internal/components");
|
|
5
|
+
var _managerApi = require("storybook/manager-api");
|
|
6
|
+
var _constants = require("../constants");
|
|
7
|
+
var _Panel = _interopRequireDefault(require("../Panel"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
9
|
+
_managerApi.addons.register(_constants.ADDON_ID, function () {
|
|
10
|
+
_managerApi.addons.add(_constants.PANEL_ID, {
|
|
11
|
+
type: _managerApi.types.PANEL,
|
|
12
|
+
title: "Tests results",
|
|
13
|
+
match: function match(_ref) {
|
|
14
|
+
var viewMode = _ref.viewMode;
|
|
15
|
+
return viewMode === "story";
|
|
16
|
+
},
|
|
17
|
+
render: function render(_ref2) {
|
|
18
|
+
var active = _ref2.active;
|
|
19
|
+
return /*#__PURE__*/_react["default"].createElement(_components.AddonPanel, {
|
|
20
|
+
active: active
|
|
21
|
+
}, /*#__PURE__*/_react["default"].createElement(_Panel["default"], null));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
4
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { PARAM_KEY } from "./constants";
|
|
9
|
+
import { useParameter } from "storybook/manager-api";
|
|
10
|
+
export function reduceFileTestResults(accumulator, assertionResult) {
|
|
11
|
+
var _assertionResult$ance = _slicedToArray(assertionResult.ancestorTitles, 2),
|
|
12
|
+
testGroupName = _assertionResult$ance[1];
|
|
13
|
+
if (!accumulator[testGroupName]) {
|
|
14
|
+
accumulator[testGroupName] = [];
|
|
15
|
+
}
|
|
16
|
+
accumulator[testGroupName].push({
|
|
17
|
+
title: assertionResult.title,
|
|
18
|
+
status: assertionResult.status
|
|
19
|
+
});
|
|
20
|
+
return accumulator;
|
|
21
|
+
}
|
|
22
|
+
export function extractFileTestsData(results, fileName) {
|
|
23
|
+
var _results$testResults;
|
|
24
|
+
var fileTestResults = (_results$testResults = results.testResults) === null || _results$testResults === void 0 ? void 0 : _results$testResults.find(function (r) {
|
|
25
|
+
return r.name.includes(fileName);
|
|
26
|
+
});
|
|
27
|
+
if (!fileTestResults) {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
return fileTestResults.assertionResults.reduce(reduceFileTestResults, {});
|
|
31
|
+
}
|
|
32
|
+
var VitestPanel = function VitestPanel() {
|
|
33
|
+
var params = useParameter(PARAM_KEY);
|
|
34
|
+
if (!params) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
var testResults = params.testResults,
|
|
38
|
+
fileName = params.testFile;
|
|
39
|
+
var fileTestResults = null;
|
|
40
|
+
if (testResults && fileName) {
|
|
41
|
+
fileTestResults = extractFileTestsData(testResults, fileName);
|
|
42
|
+
}
|
|
43
|
+
var error = null;
|
|
44
|
+
if (!fileName && !testResults) {
|
|
45
|
+
error = 'Please check your config: missing both `testFile` and `testResults`.{" "}';
|
|
46
|
+
} else if (!fileName) {
|
|
47
|
+
error = "Please check your config: missing `testFile` name.";
|
|
48
|
+
} else if (!testResults) {
|
|
49
|
+
error = "Please check your config: missing `testResults` file.";
|
|
50
|
+
} else if (!("testResults" in testResults)) {
|
|
51
|
+
error = "Please check your config: `testResults` file does not contain valid results format.";
|
|
52
|
+
} else if (!fileTestResults || Object.keys(fileTestResults).length === 0) {
|
|
53
|
+
error = "No tests found.";
|
|
54
|
+
}
|
|
55
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
56
|
+
style: {
|
|
57
|
+
padding: "1rem"
|
|
58
|
+
}
|
|
59
|
+
}, error && /*#__PURE__*/React.createElement("p", null, " ", error), fileTestResults && Object.entries(fileTestResults).map(function (_ref) {
|
|
60
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
61
|
+
title = _ref2[0],
|
|
62
|
+
group = _ref2[1];
|
|
63
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
64
|
+
key: title
|
|
65
|
+
}, /*#__PURE__*/React.createElement("strong", null, title), /*#__PURE__*/React.createElement("div", {
|
|
66
|
+
style: {
|
|
67
|
+
display: "flex",
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
rowGap: 8,
|
|
70
|
+
paddingTop: 8,
|
|
71
|
+
paddingBottom: 16
|
|
72
|
+
}
|
|
73
|
+
}, group.map(function (d) {
|
|
74
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
75
|
+
key: d.title,
|
|
76
|
+
style: {
|
|
77
|
+
display: "flex",
|
|
78
|
+
flexDirection: "row",
|
|
79
|
+
alignItems: "center",
|
|
80
|
+
columnGap: 4,
|
|
81
|
+
paddingLeft: 16
|
|
82
|
+
}
|
|
83
|
+
}, /*#__PURE__*/React.createElement("div", null, d.status === "passed" ? "✔️" : "❌"), /*#__PURE__*/React.createElement("div", null, d.title));
|
|
84
|
+
})));
|
|
85
|
+
}));
|
|
86
|
+
};
|
|
87
|
+
export default VitestPanel;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import { vi, describe, it, expect, beforeEach } from "vitest";
|
|
4
|
+
import VitestPanel from "../Panel";
|
|
5
|
+
import { sampleTestResults } from "./fixtures";
|
|
6
|
+
vi.mock("storybook/manager-api", function () {
|
|
7
|
+
return {
|
|
8
|
+
useParameter: vi.fn()
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
vi.mock("../constants", function () {
|
|
12
|
+
return {
|
|
13
|
+
PARAM_KEY: "vitest"
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
import { useParameter } from "storybook/manager-api";
|
|
17
|
+
var mockUseParameter = vi.mocked(useParameter);
|
|
18
|
+
describe("VitestPanel", function () {
|
|
19
|
+
beforeEach(function () {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
describe("when useParameter returns a falsy value", function () {
|
|
23
|
+
it("renders nothing when params are null", function () {
|
|
24
|
+
mockUseParameter.mockReturnValue(null);
|
|
25
|
+
var _render = render(/*#__PURE__*/React.createElement(VitestPanel, null)),
|
|
26
|
+
container = _render.container;
|
|
27
|
+
expect(container.firstChild).toBeNull();
|
|
28
|
+
});
|
|
29
|
+
it("renders nothing when params are undefined", function () {
|
|
30
|
+
mockUseParameter.mockReturnValue(undefined);
|
|
31
|
+
var _render2 = render(/*#__PURE__*/React.createElement(VitestPanel, null)),
|
|
32
|
+
container = _render2.container;
|
|
33
|
+
expect(container.firstChild).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("error states", function () {
|
|
37
|
+
it("shows error when both testFile and testResults are missing", function () {
|
|
38
|
+
mockUseParameter.mockReturnValue({});
|
|
39
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
40
|
+
expect(screen.getByText(/missing both `testFile` and `testResults`/)).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
it("shows error when testFile is missing but testResults is present", function () {
|
|
43
|
+
mockUseParameter.mockReturnValue({
|
|
44
|
+
testResults: sampleTestResults
|
|
45
|
+
});
|
|
46
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
47
|
+
expect(screen.getByText(/missing `testFile` name/)).toBeInTheDocument();
|
|
48
|
+
});
|
|
49
|
+
it("shows error when testResults is missing but testFile is present", function () {
|
|
50
|
+
mockUseParameter.mockReturnValue({
|
|
51
|
+
testFile: "Button.test.tsx"
|
|
52
|
+
});
|
|
53
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
54
|
+
expect(screen.getByText(/missing `testResults` file/)).toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
it("shows error when testResults object lacks the testResults property", function () {
|
|
57
|
+
mockUseParameter.mockReturnValue({
|
|
58
|
+
testFile: "Button.test.tsx",
|
|
59
|
+
testResults: {
|
|
60
|
+
success: true
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
64
|
+
expect(screen.getByText(/does not contain valid results format/)).toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
it("shows 'No tests found' when testFile does not match any result", function () {
|
|
67
|
+
mockUseParameter.mockReturnValue({
|
|
68
|
+
testFile: "NonExistent.test.tsx",
|
|
69
|
+
testResults: sampleTestResults
|
|
70
|
+
});
|
|
71
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
72
|
+
expect(screen.getByText(/No tests found/)).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe("successful rendering", function () {
|
|
76
|
+
beforeEach(function () {
|
|
77
|
+
mockUseParameter.mockReturnValue({
|
|
78
|
+
testFile: "Button.test.tsx",
|
|
79
|
+
testResults: sampleTestResults
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it("renders no error message", function () {
|
|
83
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
84
|
+
expect(screen.queryByText(/Please check your config/)).toBeNull();
|
|
85
|
+
expect(screen.queryByText(/No tests found/)).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
it("renders each test group as a bold heading", function () {
|
|
88
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
89
|
+
var headings = screen.getAllByText(/Button unit tests|Button accessibility/);
|
|
90
|
+
headings.forEach(function (el) {
|
|
91
|
+
return expect(el.tagName).toBe("STRONG");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
it("renders all test titles", function () {
|
|
95
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
96
|
+
expect(screen.getByText("renders text and children")).toBeInTheDocument();
|
|
97
|
+
expect(screen.getByText("handles click action")).toBeInTheDocument();
|
|
98
|
+
expect(screen.getByText("has correct aria label")).toBeInTheDocument();
|
|
99
|
+
});
|
|
100
|
+
it("shows ✔️ for passed tests", function () {
|
|
101
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
102
|
+
var passIcons = screen.getAllByText("✔️");
|
|
103
|
+
expect(passIcons).toHaveLength(2);
|
|
104
|
+
});
|
|
105
|
+
it("shows ❌ for failed tests", function () {
|
|
106
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
107
|
+
var failIcons = screen.getAllByText("❌");
|
|
108
|
+
expect(failIcons).toHaveLength(1);
|
|
109
|
+
});
|
|
110
|
+
it("renders the correct number of test groups", function () {
|
|
111
|
+
render(/*#__PURE__*/React.createElement(VitestPanel, null));
|
|
112
|
+
expect(screen.getByText("Button unit tests")).toBeInTheDocument();
|
|
113
|
+
expect(screen.getByText("Button accessibility")).toBeInTheDocument();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe("layout and container", function () {
|
|
117
|
+
it("wraps content in a padded div", function () {
|
|
118
|
+
mockUseParameter.mockReturnValue({
|
|
119
|
+
testFile: "Button.test.tsx",
|
|
120
|
+
testResults: sampleTestResults
|
|
121
|
+
});
|
|
122
|
+
var _render3 = render(/*#__PURE__*/React.createElement(VitestPanel, null)),
|
|
123
|
+
container = _render3.container;
|
|
124
|
+
var wrapper = container.firstChild;
|
|
125
|
+
expect(wrapper.tagName).toBe("DIV");
|
|
126
|
+
expect(wrapper.style.padding).toBe("1rem");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
export var makeAssertion = function makeAssertion() {
|
|
8
|
+
var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
9
|
+
return _objectSpread({
|
|
10
|
+
ancestorTitles: ["", "My Suite"],
|
|
11
|
+
fullName: "My Suite renders correctly",
|
|
12
|
+
title: "renders correctly",
|
|
13
|
+
duration: 10,
|
|
14
|
+
status: "passed"
|
|
15
|
+
}, overrides);
|
|
16
|
+
};
|
|
17
|
+
export var sampleTestResults = {
|
|
18
|
+
numTotalTestSuites: 1,
|
|
19
|
+
numPassedTestSuites: 1,
|
|
20
|
+
numFailedTestSuites: 0,
|
|
21
|
+
numPendingTestSuites: 0,
|
|
22
|
+
numTotalTests: 3,
|
|
23
|
+
numPassedTests: 2,
|
|
24
|
+
numFailedTests: 1,
|
|
25
|
+
numPendingTests: 0,
|
|
26
|
+
numTodoTests: 0,
|
|
27
|
+
startTime: 1698956313163,
|
|
28
|
+
success: true,
|
|
29
|
+
testResults: [{
|
|
30
|
+
assertionResults: [makeAssertion({
|
|
31
|
+
ancestorTitles: ["", "Button unit tests"],
|
|
32
|
+
title: "renders text and children",
|
|
33
|
+
status: "passed"
|
|
34
|
+
}), makeAssertion({
|
|
35
|
+
ancestorTitles: ["", "Button unit tests"],
|
|
36
|
+
title: "handles click action",
|
|
37
|
+
status: "passed"
|
|
38
|
+
}), makeAssertion({
|
|
39
|
+
ancestorTitles: ["", "Button accessibility"],
|
|
40
|
+
title: "has correct aria label",
|
|
41
|
+
status: "failed"
|
|
42
|
+
})],
|
|
43
|
+
startTime: 1698956314807,
|
|
44
|
+
endTime: 1698956314843,
|
|
45
|
+
status: "passed",
|
|
46
|
+
message: "",
|
|
47
|
+
name: "/path/to/src/components/Button/Button.test.tsx"
|
|
48
|
+
}]
|
|
49
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
5
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
6
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import { reduceFileTestResults, extractFileTestsData } from "../Panel";
|
|
9
|
+
import { makeAssertion, sampleTestResults } from "./fixtures";
|
|
10
|
+
describe("reduceFileTestResults", function () {
|
|
11
|
+
it("creates a new group for an unseen ancestorTitle", function () {
|
|
12
|
+
var result = reduceFileTestResults({}, makeAssertion());
|
|
13
|
+
expect(result).toEqual({
|
|
14
|
+
"My Suite": [{
|
|
15
|
+
title: "renders correctly",
|
|
16
|
+
status: "passed"
|
|
17
|
+
}]
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it("appends to an existing group for the same ancestorTitle", function () {
|
|
21
|
+
var initial = {
|
|
22
|
+
"My Suite": [{
|
|
23
|
+
title: "renders correctly",
|
|
24
|
+
status: "passed"
|
|
25
|
+
}]
|
|
26
|
+
};
|
|
27
|
+
var result = reduceFileTestResults(initial, makeAssertion({
|
|
28
|
+
title: "handles click",
|
|
29
|
+
status: "failed"
|
|
30
|
+
}));
|
|
31
|
+
expect(result["My Suite"]).toHaveLength(2);
|
|
32
|
+
expect(result["My Suite"][1]).toEqual({
|
|
33
|
+
title: "handles click",
|
|
34
|
+
status: "failed"
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("handles multiple distinct groups without mixing entries", function () {
|
|
38
|
+
var assertions = [makeAssertion({
|
|
39
|
+
ancestorTitles: ["", "Group A"],
|
|
40
|
+
title: "test 1"
|
|
41
|
+
}), makeAssertion({
|
|
42
|
+
ancestorTitles: ["", "Group B"],
|
|
43
|
+
title: "test 2"
|
|
44
|
+
}), makeAssertion({
|
|
45
|
+
ancestorTitles: ["", "Group A"],
|
|
46
|
+
title: "test 3"
|
|
47
|
+
})];
|
|
48
|
+
var result = assertions.reduce(reduceFileTestResults, {});
|
|
49
|
+
expect(Object.keys(result)).toEqual(["Group A", "Group B"]);
|
|
50
|
+
expect(result["Group A"]).toHaveLength(2);
|
|
51
|
+
expect(result["Group B"]).toHaveLength(1);
|
|
52
|
+
});
|
|
53
|
+
it("preserves the status value from each assertion", function () {
|
|
54
|
+
var result = reduceFileTestResults({}, makeAssertion({
|
|
55
|
+
status: "failed"
|
|
56
|
+
}));
|
|
57
|
+
expect(result["My Suite"][0].status).toBe("failed");
|
|
58
|
+
});
|
|
59
|
+
it("only stores title and status, discarding other assertion fields", function () {
|
|
60
|
+
var result = reduceFileTestResults({}, makeAssertion());
|
|
61
|
+
var entry = result["My Suite"][0];
|
|
62
|
+
expect(Object.keys(entry)).toEqual(["title", "status"]);
|
|
63
|
+
});
|
|
64
|
+
it("uses the second element of ancestorTitles as the group key", function () {
|
|
65
|
+
var assertion = makeAssertion({
|
|
66
|
+
ancestorTitles: ["ignored-parent", "actual-group"]
|
|
67
|
+
});
|
|
68
|
+
var result = reduceFileTestResults({}, assertion);
|
|
69
|
+
expect(result["actual-group"]).toBeDefined();
|
|
70
|
+
expect(result["ignored-parent"]).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe("extractFileTestsData", function () {
|
|
74
|
+
it("returns an empty object when no file matches", function () {
|
|
75
|
+
var result = extractFileTestsData(sampleTestResults, "NonExistent.test.tsx");
|
|
76
|
+
expect(result).toEqual({});
|
|
77
|
+
});
|
|
78
|
+
it("returns grouped results when the file name matches exactly", function () {
|
|
79
|
+
var result = extractFileTestsData(sampleTestResults, "Button.test.tsx");
|
|
80
|
+
expect(result).toHaveProperty("Button unit tests");
|
|
81
|
+
expect(result["Button unit tests"]).toHaveLength(2);
|
|
82
|
+
});
|
|
83
|
+
it("matches by partial file name using includes", function () {
|
|
84
|
+
var result = extractFileTestsData(sampleTestResults, "Button");
|
|
85
|
+
expect(result).toHaveProperty("Button unit tests");
|
|
86
|
+
});
|
|
87
|
+
it("groups assertion results under their respective suite names", function () {
|
|
88
|
+
var result = extractFileTestsData(sampleTestResults, "Button.test.tsx");
|
|
89
|
+
expect(Object.keys(result)).toContain("Button unit tests");
|
|
90
|
+
expect(Object.keys(result)).toContain("Button accessibility");
|
|
91
|
+
});
|
|
92
|
+
it("returns an empty object when testResults array is empty", function () {
|
|
93
|
+
var emptyResults = _objectSpread(_objectSpread({}, sampleTestResults), {}, {
|
|
94
|
+
testResults: []
|
|
95
|
+
});
|
|
96
|
+
var result = extractFileTestsData(emptyResults, "Button.test.tsx");
|
|
97
|
+
expect(result).toEqual({});
|
|
98
|
+
});
|
|
99
|
+
it("handles testResults being undefined gracefully", function () {
|
|
100
|
+
var malformed = {};
|
|
101
|
+
var result = extractFileTestsData(malformed, "Button.test.tsx");
|
|
102
|
+
expect(result).toEqual({});
|
|
103
|
+
});
|
|
104
|
+
it("returns full grouped structure for all assertion entries in the file", function () {
|
|
105
|
+
var result = extractFileTestsData(sampleTestResults, "Button.test.tsx");
|
|
106
|
+
var passedGroup = result["Button unit tests"];
|
|
107
|
+
expect(passedGroup.map(function (r) {
|
|
108
|
+
return r.title;
|
|
109
|
+
})).toEqual(["renders text and children", "handles click action"]);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AddonPanel } from "storybook/internal/components";
|
|
3
|
+
import { addons, types } from "storybook/manager-api";
|
|
4
|
+
import { ADDON_ID, PANEL_ID } from "../constants";
|
|
5
|
+
import Panel from "../Panel";
|
|
6
|
+
addons.register(ADDON_ID, function () {
|
|
7
|
+
addons.add(PANEL_ID, {
|
|
8
|
+
type: types.PANEL,
|
|
9
|
+
title: "Tests results",
|
|
10
|
+
match: function match(_ref) {
|
|
11
|
+
var viewMode = _ref.viewMode;
|
|
12
|
+
return viewMode === "story";
|
|
13
|
+
},
|
|
14
|
+
render: function render(_ref2) {
|
|
15
|
+
var active = _ref2.active;
|
|
16
|
+
return /*#__PURE__*/React.createElement(AddonPanel, {
|
|
17
|
+
active: active
|
|
18
|
+
}, /*#__PURE__*/React.createElement(Panel, null));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var decorators = [];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { GroupedTestResults, AssertionResult, VitestParams } from "./typings";
|
|
3
|
+
export declare function reduceFileTestResults(accumulator: GroupedTestResults, assertionResult: AssertionResult): GroupedTestResults;
|
|
4
|
+
export declare function extractFileTestsData(results: VitestParams["testResults"], fileName: string): GroupedTestResults;
|
|
5
|
+
declare const VitestPanel: () => React.JSX.Element | null;
|
|
6
|
+
export default VitestPanel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const decorators: any[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storybook_vitest_addon",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Adds a panel to display Vitest unit test results",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"storybook-addons",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "https://github.com/krzysztofradomski/storybook-addon-vitest"
|
|
19
19
|
},
|
|
20
|
-
"author": "Krzysztof Radomski <
|
|
20
|
+
"author": "Krzysztof Radomski <hello@radomski.dev>",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"main": "dist/cjs/index.js",
|
|
23
23
|
"module": "dist/esm/index.js",
|