@operato/app 10.8.1 → 10.10.0
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/CHANGELOG.md +44 -0
- package/dist/src/grist-editor/ox-grist-editor-code.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-code.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-code.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-json.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-json.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-json.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-privilege.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-privilege.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-privilege.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-resource-code.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-code.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-code.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-resource-id.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-id.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-id.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-object-legacy.js.map +1 -1
- package/dist/src/grist-editor/ox-grist-editor-resource-object.d.ts +1 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-object.js +2 -0
- package/dist/src/grist-editor/ox-grist-editor-resource-object.js.map +1 -1
- package/dist/src/relation/ox-relation-view.d.ts +127 -0
- package/dist/src/relation/ox-relation-view.js +319 -0
- package/dist/src/relation/ox-relation-view.js.map +1 -0
- package/dist/src/relation/relation-groups.d.ts +33 -0
- package/dist/src/relation/relation-groups.js +142 -0
- package/dist/src/relation/relation-groups.js.map +1 -0
- package/dist/src/selector/ox-selector-resource-object-legacy.js +13 -1
- package/dist/src/selector/ox-selector-resource-object-legacy.js.map +1 -1
- package/dist/src/selector/ox-selector-resource-object.d.ts +40 -2
- package/dist/src/selector/ox-selector-resource-object.js +180 -16
- package/dist/src/selector/ox-selector-resource-object.js.map +1 -1
- package/dist/test/selector-confirm-keeps-value.test.d.ts +1 -0
- package/dist/test/selector-confirm-keeps-value.test.js +108 -0
- package/dist/test/selector-confirm-keeps-value.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +61 -53
- package/test/selector-confirm-keeps-value.test.ts +127 -0
- package/translations/en.json +24 -0
- package/translations/es.json +26 -0
- package/translations/ja.json +26 -0
- package/translations/ko.json +24 -0
- package/translations/ms.json +6 -0
- package/translations/zh.json +24 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
/**
|
|
3
|
+
* 참조 팝업의 **확인이 값을 지우지 않는다.**
|
|
4
|
+
*
|
|
5
|
+
* ## 무엇을 지키나
|
|
6
|
+
*
|
|
7
|
+
* `ox-selector-resource-object` 의 확인은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이
|
|
8
|
+
* 없으므로 닫기와 같아야 한다. **값을 지우는 길은 「지정 안 함」 하나다.**
|
|
9
|
+
*
|
|
10
|
+
* ## 왜 이 시험이 있나 (2026-09-05)
|
|
11
|
+
*
|
|
12
|
+
* 전에는 `confirmCallback(this.selected)` 를 조건 없이 불렀다. 고른 것이 없으면 `selected` 가
|
|
13
|
+
* undefined 이고, 그것은 `onEmpty` 가 넘기는 것과 **똑같다** — 확인이 「지정 안 함」과 같은 일을
|
|
14
|
+
* 했다. 값을 지우는 단추가 둘이었고 그중 하나가 주 동작(채운 단추)이었다.
|
|
15
|
+
*
|
|
16
|
+
* 고른 표시는 목록을 받아올 때 그 쪽에서 값을 찾으면 켜진다. 그래서 목록이 한 쪽에 다 들어가는
|
|
17
|
+
* 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.
|
|
18
|
+
*
|
|
19
|
+
* ```
|
|
20
|
+
* [확인함] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다
|
|
21
|
+
* 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## 왜 부품을 세우지 않고 원문을 보나
|
|
25
|
+
*
|
|
26
|
+
* 이 부품은 `@operato/graphql` 의 클라이언트를 모듈 적재 시점에 끌어온다. 시험 안에서 그것을 세우면
|
|
27
|
+
* 서버가 필요하고, 그 무거움이 이 한 줄의 규칙을 지키는 값보다 크다.
|
|
28
|
+
*
|
|
29
|
+
* 대신 **그 규칙이 코드에 남아 있는지**를 본다. 조건 없이 부르는 모양으로 되돌아가면 빨갛게 난다.
|
|
30
|
+
* 부품을 세우는 시험은 그래프가 가벼워지면 그때 더한다.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* `onConfirm` 의 본문만 떼어 낸다.
|
|
34
|
+
*
|
|
35
|
+
* 처음에 `indexOf('fetchHandler')` 를 끝 경계로 썼다가 빈 문자열이 나왔다 — 그 낱말은 render 의
|
|
36
|
+
* 템플릿(`.fetchHandler=…`)에 **먼저** 나온다. 메서드 선언을 경계로 삼는다.
|
|
37
|
+
*/
|
|
38
|
+
function onConfirmBody(source) {
|
|
39
|
+
const start = source.indexOf(' onConfirm() {');
|
|
40
|
+
if (start < 0)
|
|
41
|
+
return '';
|
|
42
|
+
const rest = source.slice(start);
|
|
43
|
+
const end = rest.indexOf('\n }');
|
|
44
|
+
return end < 0 ? rest : rest.slice(0, end + 4);
|
|
45
|
+
}
|
|
46
|
+
describe('참조 선택기 · 확인은 값을 지우지 않는다', () => {
|
|
47
|
+
let source;
|
|
48
|
+
before(async () => {
|
|
49
|
+
const response = await fetch('/src/selector/ox-selector-resource-object.ts');
|
|
50
|
+
expect(response.ok, '원문을 읽을 수 있어야 한다').to.be.true;
|
|
51
|
+
source = await response.text();
|
|
52
|
+
});
|
|
53
|
+
it('확인은 고른 것이 없으면 콜백을 부르지 않는다', () => {
|
|
54
|
+
const body = onConfirmBody(source);
|
|
55
|
+
expect(body, 'onConfirm 을 찾아야 한다').to.include('onConfirm');
|
|
56
|
+
/*
|
|
57
|
+
* 고른 것이 없을 때 빠져나가는 길이 있어야 한다.
|
|
58
|
+
*
|
|
59
|
+
* 조건 안에 다른 절이 더 붙어도 통과시킨다 — 여럿 고르기가 들어오면서 빈 배열도 함께 봐야
|
|
60
|
+
* 했다. 지키려는 것은 「!selected 를 보고 닫고 끝낸다」이지 조건의 글자 수가 아니다.
|
|
61
|
+
*/
|
|
62
|
+
expect(body.replace(/\s+/g, ' '), '고른 것이 없으면 닫고 끝낸다').to.match(/if\s*\([^)]*!\s*selected[^{]*\)\s*\{\s*closePopup\(this\)\s*;?\s*return/);
|
|
63
|
+
});
|
|
64
|
+
it('확인이 넘기는 것은 고른 것 하나다 — this.selected 를 조건 없이 넘기지 않는다', () => {
|
|
65
|
+
const body = onConfirmBody(source).replace(/\s+/g, ' ');
|
|
66
|
+
/*
|
|
67
|
+
* 되돌아간 모양을 직접 막는다. 주석 안에 같은 글자가 있어도 걸리지 않도록 앞의 주석을 걷는다.
|
|
68
|
+
*/
|
|
69
|
+
const code = body.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
70
|
+
expect(code, '조건 없이 this.selected 를 넘기는 모양으로 돌아가면 안 된다').to.not.include('confirmCallback(this.selected)');
|
|
71
|
+
});
|
|
72
|
+
it('값을 지우는 길은 지정 안 함 하나다', () => {
|
|
73
|
+
const empty = source.slice(source.indexOf('onEmpty()'), source.indexOf('onCancel()')).replace(/\s+/g, ' ');
|
|
74
|
+
/* 인자 없이 부르는 것이 「지우기」의 뜻이다. */
|
|
75
|
+
expect(empty, '지정 안 함은 빈 값을 넘긴다').to.include('confirmCallback()');
|
|
76
|
+
});
|
|
77
|
+
/**
|
|
78
|
+
* 그리스트에 **빈 data 를 넘기지 않는다.**
|
|
79
|
+
*
|
|
80
|
+
* data-grist 는 data 가 설정되면 reset() 한다. 이 부품은 fetchHandler 로 목록을 채우면서
|
|
81
|
+
* `.data` 로 늘 ZERO_DATA 를 함께 넘기고 있었다. 그래서 이 부품이 다시 그려지는 순간 빈 값이
|
|
82
|
+
* 내려가 목록이 통째로 사라졌다.
|
|
83
|
+
*
|
|
84
|
+
* ```
|
|
85
|
+
* [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서
|
|
89
|
+
* 드러났고, 그것을 되돌리는 대신 이 바인딩을 걷었다.
|
|
90
|
+
*/
|
|
91
|
+
it('ox-grist 에 .data 를 넘기지 않는다', () => {
|
|
92
|
+
const template = source.slice(source.indexOf('<ox-grist'), source.indexOf('</ox-grist>'));
|
|
93
|
+
expect(template, 'ox-grist 를 찾아야 한다').to.include('.fetchHandler=');
|
|
94
|
+
expect(template.replace(/<!--[\s\S]*?-->/g, ''), '.data 를 다시 넘기면 목록이 사라진다').to.not.include('.data=');
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* **여럿 고르기에서 빈 배열도 막는다.**
|
|
98
|
+
*
|
|
99
|
+
* multiple 을 켜면 `selected` 가 배열이다. 아무것도 안 고른 상태는 undefined 가 아니라 `[]` 이고,
|
|
100
|
+
* 그것은 truthy 다 — `!selected` 만으로는 빠져나가지 못하고 빈 배열이 그대로 넘어간다. 받는 쪽이
|
|
101
|
+
* 그것을 「전부 지워라」로 읽으면 하나만 고르기 때와 같은 데이터 손실이 난다.
|
|
102
|
+
*/
|
|
103
|
+
it('여럿 고르기에서 빈 배열을 넘기지 않는다', () => {
|
|
104
|
+
const body = onConfirmBody(source).replace(/\s+/g, ' ');
|
|
105
|
+
expect(body, '빈 배열도 걸러야 한다').to.match(/Array\.isArray\(selected\)\s*&&\s*selected\.length\s*===?\s*0/);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=selector-confirm-keeps-value.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-confirm-keeps-value.test.js","sourceRoot":"","sources":["../../test/selector-confirm-keeps-value.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;;;;;GAKG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC/C,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACjC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,MAAc,CAAA;IAElB,MAAM,CAAC,KAAK,IAAI,EAAE;QAChB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,8CAA8C,CAAC,CAAA;QAC5E,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAA;QACjD,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;QAElC,MAAM,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QAE1D;;;;;WAKG;QACH,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,KAAK,CAC5D,yEAAyE,CAC1E,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAEvD;;WAEG;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;QAElD,MAAM,CAAC,IAAI,EAAE,0CAA0C,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CACrE,gCAAgC,CACjC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAE1G,8BAA8B;QAC9B,MAAM,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF;;;;;;;;;;;;;OAaG;IACH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAA;QAEzF,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;QAClE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,EAAE,yBAAyB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CACxF,QAAQ,CACT,CAAA;IACH,CAAC,CAAC,CAAA;IAEF;;;;;;OAMG;IACH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAEvD,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAA;IACxG,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect } from '@open-wc/testing'\n\n/**\n * 참조 팝업의 **확인이 값을 지우지 않는다.**\n *\n * ## 무엇을 지키나\n *\n * `ox-selector-resource-object` 의 확인은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이\n * 없으므로 닫기와 같아야 한다. **값을 지우는 길은 「지정 안 함」 하나다.**\n *\n * ## 왜 이 시험이 있나 (2026-09-05)\n *\n * 전에는 `confirmCallback(this.selected)` 를 조건 없이 불렀다. 고른 것이 없으면 `selected` 가\n * undefined 이고, 그것은 `onEmpty` 가 넘기는 것과 **똑같다** — 확인이 「지정 안 함」과 같은 일을\n * 했다. 값을 지우는 단추가 둘이었고 그중 하나가 주 동작(채운 단추)이었다.\n *\n * 고른 표시는 목록을 받아올 때 그 쪽에서 값을 찾으면 켜진다. 그래서 목록이 한 쪽에 다 들어가는\n * 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.\n *\n * ```\n * [확인함] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다\n * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다\n * ```\n *\n * ## 왜 부품을 세우지 않고 원문을 보나\n *\n * 이 부품은 `@operato/graphql` 의 클라이언트를 모듈 적재 시점에 끌어온다. 시험 안에서 그것을 세우면\n * 서버가 필요하고, 그 무거움이 이 한 줄의 규칙을 지키는 값보다 크다.\n *\n * 대신 **그 규칙이 코드에 남아 있는지**를 본다. 조건 없이 부르는 모양으로 되돌아가면 빨갛게 난다.\n * 부품을 세우는 시험은 그래프가 가벼워지면 그때 더한다.\n */\n/**\n * `onConfirm` 의 본문만 떼어 낸다.\n *\n * 처음에 `indexOf('fetchHandler')` 를 끝 경계로 썼다가 빈 문자열이 나왔다 — 그 낱말은 render 의\n * 템플릿(`.fetchHandler=…`)에 **먼저** 나온다. 메서드 선언을 경계로 삼는다.\n */\nfunction onConfirmBody(source: string): string {\n const start = source.indexOf(' onConfirm() {')\n if (start < 0) return ''\n const rest = source.slice(start)\n const end = rest.indexOf('\\n }')\n return end < 0 ? rest : rest.slice(0, end + 4)\n}\n\ndescribe('참조 선택기 · 확인은 값을 지우지 않는다', () => {\n let source: string\n\n before(async () => {\n const response = await fetch('/src/selector/ox-selector-resource-object.ts')\n expect(response.ok, '원문을 읽을 수 있어야 한다').to.be.true\n source = await response.text()\n })\n\n it('확인은 고른 것이 없으면 콜백을 부르지 않는다', () => {\n const body = onConfirmBody(source)\n\n expect(body, 'onConfirm 을 찾아야 한다').to.include('onConfirm')\n\n /*\n * 고른 것이 없을 때 빠져나가는 길이 있어야 한다.\n *\n * 조건 안에 다른 절이 더 붙어도 통과시킨다 — 여럿 고르기가 들어오면서 빈 배열도 함께 봐야\n * 했다. 지키려는 것은 「!selected 를 보고 닫고 끝낸다」이지 조건의 글자 수가 아니다.\n */\n expect(body.replace(/\\s+/g, ' '), '고른 것이 없으면 닫고 끝낸다').to.match(\n /if\\s*\\([^)]*!\\s*selected[^{]*\\)\\s*\\{\\s*closePopup\\(this\\)\\s*;?\\s*return/\n )\n })\n\n it('확인이 넘기는 것은 고른 것 하나다 — this.selected 를 조건 없이 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n /*\n * 되돌아간 모양을 직접 막는다. 주석 안에 같은 글자가 있어도 걸리지 않도록 앞의 주석을 걷는다.\n */\n const code = body.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n\n expect(code, '조건 없이 this.selected 를 넘기는 모양으로 돌아가면 안 된다').to.not.include(\n 'confirmCallback(this.selected)'\n )\n })\n\n it('값을 지우는 길은 지정 안 함 하나다', () => {\n const empty = source.slice(source.indexOf('onEmpty()'), source.indexOf('onCancel()')).replace(/\\s+/g, ' ')\n\n /* 인자 없이 부르는 것이 「지우기」의 뜻이다. */\n expect(empty, '지정 안 함은 빈 값을 넘긴다').to.include('confirmCallback()')\n })\n\n /**\n * 그리스트에 **빈 data 를 넘기지 않는다.**\n *\n * data-grist 는 data 가 설정되면 reset() 한다. 이 부품은 fetchHandler 로 목록을 채우면서\n * `.data` 로 늘 ZERO_DATA 를 함께 넘기고 있었다. 그래서 이 부품이 다시 그려지는 순간 빈 값이\n * 내려가 목록이 통째로 사라졌다.\n *\n * ```\n * [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건\n * ```\n *\n * 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서\n * 드러났고, 그것을 되돌리는 대신 이 바인딩을 걷었다.\n */\n it('ox-grist 에 .data 를 넘기지 않는다', () => {\n const template = source.slice(source.indexOf('<ox-grist'), source.indexOf('</ox-grist>'))\n\n expect(template, 'ox-grist 를 찾아야 한다').to.include('.fetchHandler=')\n expect(template.replace(/<!--[\\s\\S]*?-->/g, ''), '.data 를 다시 넘기면 목록이 사라진다').to.not.include(\n '.data='\n )\n })\n\n /**\n * **여럿 고르기에서 빈 배열도 막는다.**\n *\n * multiple 을 켜면 `selected` 가 배열이다. 아무것도 안 고른 상태는 undefined 가 아니라 `[]` 이고,\n * 그것은 truthy 다 — `!selected` 만으로는 빠져나가지 못하고 빈 배열이 그대로 넘어간다. 받는 쪽이\n * 그것을 「전부 지워라」로 읽으면 하나만 고르기 때와 같은 데이터 손실이 난다.\n */\n it('여럿 고르기에서 빈 배열을 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n expect(body, '빈 배열도 걸러야 한다').to.match(/Array\\.isArray\\(selected\\)\\s*&&\\s*selected\\.length\\s*===?\\s*0/)\n })\n})\n"]}
|