Skip to content

Commit c0c965c

Browse files
EmbraceAnwhale
authored andcommitted
test(utils): add tests for compareKnowledgeBaseChange;
* test(utils): add tests for compareKnowledgeBaseChange; ci: run only relevant tests in workflow * ci: normalize changed paths for test selection to be relative to working dir * ci: Unit test triggering conditions
1 parent dca8879 commit c0c965c

File tree

4 files changed

+151
-36
lines changed

4 files changed

+151
-36
lines changed

.github/workflows/Essential-tests.yml

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
pull_request:
99
branches: [test]
1010
paths:
11-
- 'app/renderer/src/main/src/release/**'
11+
- 'app/renderer/src/main/src/__tests__/**'
1212
- '.github/workflows/**'
1313

1414
jobs:
@@ -35,6 +35,7 @@ jobs:
3535
app/renderer/engine-link-startup/yarn.lock
3636
3737
- name: Cache Yarn cache
38+
id: yarn-cache
3839
uses: actions/cache@v4
3940
with:
4041
path: ~/.cache/yarn
@@ -43,6 +44,7 @@ jobs:
4344
${{ runner.os }}-yarn-cache-
4445
4546
- name: Cache node_modules
47+
id: node-mod-cache
4648
uses: actions/cache@v4
4749
with:
4850
path: app/renderer/src/main/node_modules
@@ -51,9 +53,14 @@ jobs:
5153
${{ runner.os }}-node-modules-
5254
5355
- name: Install dependencies (renderer main)
56+
if: steps.node-mod-cache.outputs.cache-hit != 'true'
5457
working-directory: app/renderer/src/main
5558
run: yarn install --frozen-lockfile --prefer-offline --network-concurrency 1
5659

60+
- name: Skip install (node_modules cache hit)
61+
if: steps.node-mod-cache.outputs.cache-hit == 'true'
62+
run: echo "node_modules cache restored; skipping yarn install"
63+
5764
- name: Verify installed packages (quick)
5865
working-directory: app/renderer/src/main
5966
run: |
@@ -70,8 +77,73 @@ jobs:
7077
echo "Show specific folder (if exists):"
7178
ls -la src/components/playground/Vitest__Test__ || true
7279
80+
- name: Determine relevant test files
81+
id: test_selection
82+
working-directory: app/renderer/src/main
83+
shell: bash
84+
run: |
85+
# Get files changed in the PR. Use multiple fallbacks because the runner
86+
# may have a shallow checkout and referenced commits might not exist.
87+
CHANGED=""
88+
89+
# 1) Try the standard range if both commits are present
90+
if git rev-parse --verify "${{ github.event.before }}" >/dev/null 2>&1 && git rev-parse --verify "${{ github.sha }}" >/dev/null 2>&1; then
91+
CHANGED=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" || true)
92+
fi
93+
94+
# 2) If still empty, try fetching the base branch (for PRs) and compare
95+
if [ -z "$CHANGED" ] && [ -n "${{ github.event.pull_request.base.ref }}" ]; then
96+
echo "Standard range not available — fetching base branch ${{ github.event.pull_request.base.ref }}"
97+
git fetch --no-tags --depth=1 origin "${{ github.event.pull_request.base.ref }}" || true
98+
BASE_REF="origin/${{ github.event.pull_request.base.ref }}"
99+
CHANGED=$(git diff --name-only "$BASE_REF" "${{ github.sha }}" || true)
100+
fi
101+
102+
# 3) Final fallback: use files from the last commit(s)
103+
if [ -z "$CHANGED" ]; then
104+
echo "Falling back to last commit changes"
105+
CHANGED=$(git diff --name-only HEAD^ HEAD || git show --name-only --pretty= "" "${{ github.sha }}" || true)
106+
fi
107+
108+
echo "Changed files:\n$CHANGED"
109+
110+
# Normalize changed paths to be relative to the working dir by
111+
# taking the last occurrence of 'src/' (works for nested 'src' paths)
112+
CHANGED_REL=$(printf "%s\n" "$CHANGED" | awk -F'src/' '{ if (NF>1) print "src/"$(NF) ; else print $0 }' | sort -u || true)
113+
# remove empty lines
114+
CHANGED_REL=$(printf "%s\n" "$CHANGED_REL" | sed '/^$/d' || true)
115+
echo "Normalized changes:\n$CHANGED_REL"
116+
117+
# Prefer explicitly changed test files
118+
TEST_FILES=$(printf "%s\n" "$CHANGED_REL" | grep -E 'src/.*\.(test|spec)\.(ts|tsx|js|jsx)' || true)
119+
if [ -n "$TEST_FILES" ]; then
120+
TF=$(echo "$TEST_FILES" | tr '\n' ' ')
121+
echo "Found test files: $TF"
122+
echo "tests=$TF" >> $GITHUB_OUTPUT
123+
exit 0
124+
fi
125+
126+
# Otherwise, map changed source dirs to test globs
127+
DIRS=$(printf "%s\n" "$CHANGED_REL" | grep -E '^src/' || true)
128+
if [ -n "$DIRS" ]; then
129+
PATTERNS=$(printf "%s\n" "$DIRS" | sed -E 's|/[^/]+$||' | sort -u | awk '{print $0"/**/*.test.* "$0"/**/*.spec.*"}' | tr '\n' ' ')
130+
echo "Derived patterns: $PATTERNS"
131+
echo "tests=$PATTERNS" >> $GITHUB_OUTPUT
132+
exit 0
133+
fi
134+
135+
echo "No relevant tests found to run"
136+
echo "tests=none" >> $GITHUB_OUTPUT
137+
73138
- name: Run Vitest (renderer main)
74139
working-directory: app/renderer/src/main
75140
env:
76141
CI: true
77-
run: yarn test:vitest -- --run --reporter verbose
142+
run: |
143+
TESTS="${{ steps.test_selection.outputs.tests }}"
144+
if [ "$TESTS" = "none" ]; then
145+
echo "No relevant tests changed, skipping vitest"
146+
exit 0
147+
fi
148+
echo "Running tests: $TESTS"
149+
yarn test:vitest -- $TESTS -- --run --reporter verbose
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {describe, it, expect} from "vitest"
2+
import {compareKnowledgeBaseChange} from "@/components/playground/Vitest__Test__/utils"
3+
4+
describe("compareKnowledgeBaseChange", () => {
5+
it("returns true when prev or next is not an array", () => {
6+
expect(compareKnowledgeBaseChange(null, [])).toBe(true)
7+
expect(compareKnowledgeBaseChange([], undefined)).toBe(true)
8+
})
9+
10+
it("detects a deleted item", () => {
11+
const prev = [{ID: "1", name: "a"}, {ID: "2", name: "b"}]
12+
const next = [{ID: "2", name: "b"}]
13+
14+
const res = compareKnowledgeBaseChange(prev as any, next as any)
15+
expect(res).toEqual({delete: prev[0], increase: null})
16+
})
17+
18+
it("detects an increased item", () => {
19+
const prev = [{ID: "1", name: "a"}]
20+
const next = [{ID: "1", name: "a"}, {ID: "2", name: "b"}]
21+
22+
const res = compareKnowledgeBaseChange(prev as any, next as any)
23+
expect(res).toEqual({delete: null, increase: next[1]})
24+
})
25+
26+
it("returns true when there is no change", () => {
27+
const prev = [{ID: "1"}, {ID: "2"}]
28+
const next = [{ID: "1"}, {ID: "2"}]
29+
expect(compareKnowledgeBaseChange(prev as any, next as any)).toBe(true)
30+
})
31+
})
Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {OperationRecordRes} from "@/components/yakitUI/YakitEditor/YakitEditorType"
21
import {YakitSpin} from "@/components/yakitUI/YakitSpin/YakitSpin"
32
import {getRemoteValue} from "@/utils/kv"
43
import {useSafeState} from "ahooks"
@@ -11,47 +10,30 @@ interface VitestTestProps {
1110
const Vitest__Test__: FC<VitestTestProps> = (props) => {
1211
const {editorOperationRecord} = props
1312
const [typeLoading, setTypeLoading] = useSafeState<boolean>(true)
14-
const [fontSize, setFontSize] = useSafeState<undefined | number>(12)
15-
const [showLineBreaks, setShowLineBreaks] = useSafeState<boolean>(true)
16-
const [noWordwrap, setNoWordwrap] = useSafeState(false)
1713

1814
useEffect(() => {
19-
if (!editorOperationRecord) {
20-
setTypeLoading(false)
21-
return
22-
}
2315
setTypeLoading(true)
24-
getRemoteValue(editorOperationRecord)
25-
.then((data) => {
26-
try {
27-
setTypeLoading(false)
28-
if (!data) return
29-
let obj: OperationRecordRes = JSON.parse(data)
30-
if (obj?.fontSize) {
31-
setFontSize(obj?.fontSize)
32-
}
33-
if (typeof obj?.showBreak === "boolean") {
34-
setShowLineBreaks(obj?.showBreak)
16+
if (editorOperationRecord) {
17+
getRemoteValue(editorOperationRecord)
18+
.then((data) => {
19+
try {
20+
setTypeLoading(false)
21+
if (!data) return
22+
} catch (error) {
23+
setTypeLoading(false)
24+
fail(error + "")
3525
}
36-
if (typeof obj?.noWordWrap === "boolean") {
37-
setNoWordwrap(obj?.noWordWrap)
38-
}
39-
} catch (error) {
26+
})
27+
.finally(() => {
4028
setTypeLoading(false)
41-
fail(error + "")
42-
}
43-
})
44-
.finally(() => {
45-
setTypeLoading(false)
46-
})
29+
})
30+
} else {
31+
setTypeLoading(false)
32+
}
4733
// eslint-disable-next-line react-hooks/exhaustive-deps
4834
}, [editorOperationRecord])
4935

50-
return (
51-
<YakitSpin spinning={typeLoading}>
52-
<div>Vitest__Test__</div>
53-
</YakitSpin>
54-
)
36+
return <YakitSpin spinning={typeLoading}>vitest test page</YakitSpin>
5537
}
5638

5739
export {Vitest__Test__}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {KnowledgeBaseItem} from "@/pages/KnowledgeBase/hooks/useKnowledgeBase"
2+
3+
/**
4+
* 对比两个知识库数组,判断新增或删除
5+
* @param prev 上一次的数据
6+
* @param next 当前的数据
7+
*/
8+
const compareKnowledgeBaseChange = (
9+
prev: KnowledgeBaseItem[] | null | undefined,
10+
next: KnowledgeBaseItem[] | null | undefined
11+
): {delete: KnowledgeBaseItem | null; increase: KnowledgeBaseItem | null} | true => {
12+
// 如果任意一方为空,则无法比较,直接返回 true(表示无变化或无法判断)
13+
if (!Array.isArray(prev) || !Array.isArray(next)) return true
14+
15+
const prevMap = new Map(prev.map((item) => [item.ID, item]))
16+
const nextMap = new Map(next.map((item) => [item.ID, item]))
17+
18+
// 查找被删除的对象
19+
const deleted = prev.find((item) => !nextMap.has(item.ID))
20+
if (deleted) return {delete: deleted, increase: null}
21+
22+
// 查找新增的对象
23+
const increased = next.find((item) => !prevMap.has(item.ID))
24+
if (increased) return {delete: null, increase: increased}
25+
26+
// 没有变化
27+
return true
28+
}
29+
30+
export {compareKnowledgeBaseChange}

0 commit comments

Comments
 (0)