mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-10 03:29:50 +08:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2418c47764 | ||
|
|
04d34534fd | ||
|
|
17ea4811fb |
@@ -43,8 +43,14 @@ jobs:
|
|||||||
run: npm --prefix packages/mcp-server run build && npm --prefix packages/mcp-server run check-package
|
run: npm --prefix packages/mcp-server run build && npm --prefix packages/mcp-server run check-package
|
||||||
|
|
||||||
e2e:
|
e2e:
|
||||||
name: E2E Tests
|
# Six jobs at once, each with a sixth of the tests and one worker: the
|
||||||
|
# same conditions per test, a fraction of the time
|
||||||
|
name: E2E Tests (${{ matrix.shard }}/6)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shard: [1, 2, 3, 4, 5, 6]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
@@ -76,7 +82,7 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
run: npm run test:e2e
|
run: npm run test:e2e -- --shard=${{ matrix.shard }}/6
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
@@ -84,6 +90,6 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v6
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
name: playwright-report-${{ matrix.shard }}
|
||||||
path: playwright-report/
|
path: playwright-report/
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|||||||
@@ -216,6 +216,20 @@ export function applyDiagramOperations(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A cut-off cell (its XML still streaming in a preview) would
|
||||||
|
// parse in Chrome to a cell without its geometry
|
||||||
|
const syntaxError = getXmlSyntaxError(
|
||||||
|
`<wrapper>${op.new_xml}</wrapper>`,
|
||||||
|
)
|
||||||
|
if (syntaxError) {
|
||||||
|
errors.push({
|
||||||
|
type: "update",
|
||||||
|
cellId: op.cell_id,
|
||||||
|
message: `new_xml is not well-formed XML: ${syntaxError}`,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the new XML
|
// Parse the new XML
|
||||||
const newDoc = parser.parseFromString(
|
const newDoc = parser.parseFromString(
|
||||||
`<wrapper>${op.new_xml}</wrapper>`,
|
`<wrapper>${op.new_xml}</wrapper>`,
|
||||||
@@ -268,6 +282,20 @@ export function applyDiagramOperations(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A cut-off cell (its XML still streaming in a preview) would
|
||||||
|
// parse in Chrome to a cell without its geometry
|
||||||
|
const syntaxError = getXmlSyntaxError(
|
||||||
|
`<wrapper>${op.new_xml}</wrapper>`,
|
||||||
|
)
|
||||||
|
if (syntaxError) {
|
||||||
|
errors.push({
|
||||||
|
type: "add",
|
||||||
|
cellId: op.cell_id,
|
||||||
|
message: `new_xml is not well-formed XML: ${syntaxError}`,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the new XML
|
// Parse the new XML
|
||||||
const newDoc = parser.parseFromString(
|
const newDoc = parser.parseFromString(
|
||||||
`<wrapper>${op.new_xml}</wrapper>`,
|
`<wrapper>${op.new_xml}</wrapper>`,
|
||||||
|
|||||||
@@ -149,3 +149,52 @@ describe("a wrapped mxCell with its wrapper's id", () => {
|
|||||||
expect(result).toContain('label="B"')
|
expect(result).toContain('label="B"')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("cut-off new_xml", () => {
|
||||||
|
// While edit_diagram streams, the last operation's XML is often
|
||||||
|
// incomplete. Chrome's DOMParser keeps the partial cell, so it must be
|
||||||
|
// refused before it reaches the diagram.
|
||||||
|
const CUT = `<mxCell id="b" value="B2" style="rounded=1;" vertex="1" parent="1">`
|
||||||
|
|
||||||
|
it("refuses an update whose XML is cut off", () => {
|
||||||
|
const { result, errors } = applyDiagramOperations(DOC, [
|
||||||
|
{ operation: "update", cell_id: "b", new_xml: CUT },
|
||||||
|
])
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
expect(errors[0]).toMatchObject({ type: "update", cellId: "b" })
|
||||||
|
expect(errors[0].message).toContain("not well-formed")
|
||||||
|
expect(result).toContain('value="B"')
|
||||||
|
expect(result).not.toContain("B2")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("refuses an add whose XML is cut off", () => {
|
||||||
|
const { result, errors } = applyDiagramOperations(DOC, [
|
||||||
|
{
|
||||||
|
operation: "add",
|
||||||
|
cell_id: "n",
|
||||||
|
new_xml: `<mxCell id="n" value="N" vertex="1" parent="1"><mxGeometry x="1" y="2" width="3"`,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
expect(errors[0]).toMatchObject({ type: "add", cellId: "n" })
|
||||||
|
expect(result).not.toContain('id="n"')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("applies the complete operations before a cut-off one", () => {
|
||||||
|
const { result, errors } = applyDiagramOperations(DOC, [
|
||||||
|
{
|
||||||
|
operation: "update",
|
||||||
|
cell_id: "b",
|
||||||
|
new_xml: `<mxCell id="b" value="B3" vertex="1" parent="1"><mxGeometry as="geometry"/></mxCell>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operation: "add",
|
||||||
|
cell_id: "n",
|
||||||
|
new_xml: `<mxCell id="n" value="N" vertex="1" parent="1">`,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
expect(result).toContain('value="B3"')
|
||||||
|
expect(result).not.toContain('id="n"')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user