test(import): add a synthetic export.xml fixture for the origin marker

The fixture is invented, in the shape Apple's DTD documents, and says so in its
header and its file name. It shows the parser reads a file laid out like an
export; it cannot show that Apple writes a custom metadata key verbatim.
This commit is contained in:
BernhardBuckel committed 2026-10-04 11:10:49 +02:00
1 parent a5e98c9e71
commit 841d4e559c
2 files changed
+85

No files matched your search

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
SYNTHETIC FIXTURE. Not an export from a real person or device.
Written by hand to the shape Apple's export.xml documents in its own DTD
(abridged below): a <Record> may hold <MetadataEntry key= value=> children.
Every value, date and id is invented. What it cannot show is whether Apple's
exporter writes a custom metadata key such as dev.healthlog.app.origin
verbatim; that has to be checked against a real export (see #1109).
Records, in order:
1. weight 80.1 carries the HealthLog origin marker -> left out
2. weight 80.2 user-entered, no marker -> imported
3. weight 80.3 marker among other metadata entries -> left out
4. weight 80.4 no metadata at all -> imported
5. weight 80.5 origin key with another value -> imported
-->
<!DOCTYPE HealthData [
<!ELEMENT HealthData (ExportDate, Me, Record*)>
<!ATTLIST HealthData locale CDATA #REQUIRED>
<!ELEMENT ExportDate EMPTY>
<!ATTLIST ExportDate value CDATA #REQUIRED>
<!ELEMENT Me EMPTY>
<!ELEMENT Record (MetadataEntry*)>
<!ATTLIST Record
type CDATA #REQUIRED
unit CDATA #IMPLIED
value CDATA #IMPLIED
sourceName CDATA #REQUIRED
sourceVersion CDATA #IMPLIED
device CDATA #IMPLIED
creationDate CDATA #IMPLIED
startDate CDATA #REQUIRED
endDate CDATA #REQUIRED>
<!ELEMENT MetadataEntry EMPTY>
<!ATTLIST MetadataEntry key CDATA #REQUIRED value CDATA #REQUIRED>
]>
<HealthData locale="en_US">
<ExportDate value="2026-05-20 12:00:00 +0200"/>
<Me/>
<Record type="HKQuantityTypeIdentifierBodyMass" sourceName="SyntheticApp" unit="kg" creationDate="2026-05-14 08:00:02 +0200" startDate="2026-05-14 08:00:00 +0200" endDate="2026-05-14 08:00:00 +0200" value="80.1">
<MetadataEntry key="dev.healthlog.app.origin" value="healthlog"/>
<MetadataEntry key="HKExternalUUID" value="00000000-0000-0000-0000-000000000001"/>
</Record>
<Record type="HKQuantityTypeIdentifierBodyMass" sourceName="SyntheticApp" unit="kg" creationDate="2026-05-14 09:00:02 +0200" startDate="2026-05-14 09:00:00 +0200" endDate="2026-05-14 09:00:00 +0200" value="80.2">
<MetadataEntry key="HKWasUserEntered" value="1"/>
</Record>
<Record type="HKQuantityTypeIdentifierBodyMass" sourceName="SyntheticApp" unit="kg" creationDate="2026-05-14 10:00:02 +0200" startDate="2026-05-14 10:00:00 +0200" endDate="2026-05-14 10:00:00 +0200" value="80.3">
<MetadataEntry key="HKWasUserEntered" value="1"/>
<MetadataEntry key="dev.healthlog.app.origin" value="healthlog"/>
</Record>
<Record type="HKQuantityTypeIdentifierBodyMass" sourceName="SyntheticApp" unit="kg" creationDate="2026-05-14 11:00:02 +0200" startDate="2026-05-14 11:00:00 +0200" endDate="2026-05-14 11:00:00 +0200" value="80.4"/>
<Record type="HKQuantityTypeIdentifierBodyMass" sourceName="SyntheticApp" unit="kg" creationDate="2026-05-14 12:00:02 +0200" startDate="2026-05-14 12:00:00 +0200" endDate="2026-05-14 12:00:00 +0200" value="80.5">
<MetadataEntry key="dev.healthlog.app.origin" value="some-other-app"/>
</Record>
</HealthData>
@@ -116,6 +116,35 @@ describe("a record HealthLog wrote itself (the origin marker)", () => {
});
});
describe("the synthetic export fixture", () => {
// `export-own-origin.synthetic.xml` is invented, in the shape Apple's DTD
// documents. It shows the parser reads a file laid out like an export; it
// cannot show that Apple writes a custom metadata key verbatim.
it("leaves out the two marked records and imports the other three", async () => {
const user = await prisma.user.create({
data: { username: "own-fixture", email: "fx@example.test", role: "USER" },
});
const result = await streamParseExportXml({
xmlPath: join(
process.cwd(),
"tests/fixtures/apple-health/export-own-origin.synthetic.xml",
),
userId: user.id,
userTimezone: "Europe/Berlin",
prisma,
});
const rows = await prisma.measurement.findMany({
where: { userId: user.id, type: "WEIGHT", source: "APPLE_HEALTH" },
orderBy: { measuredAt: "asc" },
});
expect(rows.map((r) => r.value)).toEqual([80.2, 80.4, 80.5]);
expect(result.writtenByHealthLog).toEqual({
byMarker: 2,
matchedManual: 0,
});
});
});
describe("a manual entry mirrored before the marker existed", () => {
async function runAgainst(
manual: { value: number; at: string; source?: "MANUAL" | "WITHINGS" },