Created: 2026-03-17
ExportInkjetFile(KitID) produces the inkjet operator CSV used on press day. It has zero automated coverage. The function joins InkjetRecords + KitLabels + Colors from an Access MDB, builds a Chilkat CSV with 22 columns, writes it to disk, then marks Kit.Status='Done’. A regression here causes silent bad output with no test catching it.
Add an ADODB integration test directly to Tests/TrackingDataImport_TestHarness.vbs. The harness opens Data/webdata - Copy.mdb via ADODB, calls ExportInkjetFile on a real KitID, and asserts CSV structure (file exists, 22 columns, correct headers) plus ~10 row-level field values and the DB side-effect (Kit.Status='Done’, InkJetJob=1).
In Scope:
oConn, ConnectionString (pointing to Data/webdata - Copy.mdb), ExportDirectory (temp path under Tests/)GetSetting and ExportInkjetFile into the functionNames arrayExportInkjetFile(KitID)Out of Scope:
ExportInkjetFile (not viable — all field assembly is inline with recordset reads; refactoring would be required)Data/webdata - Copy.mdb)webdata.mdb is untouched)LoadFunctions(filePath, functionNames) extracts named functions from source via text parsing; ExecuteGlobal makes them available in harness global scope. Global vars set before calling functions are visible inside loaded functions.LoadFunctions is called at line 34, before any test code. Adding "GetSetting" and "ExportInkjetFile" to the functionNames array (lines 16–32) is sufficient — they'll be extracted and available globally.Set objFSO = fso at line 36 — already set. ExportInkjetFile uses objFSO internally; this is already satisfied.chilkatAvailable declared at line 39 — already exists. New integrationDbAvailable follows the same declare-in-preamble, set-in-init-block pattern.Assert sub — only AssertEqual(actual, expected, label) and AssertArrayEqual. All integration test assertions must use AssertEqual condition, True, "label" form.ExportInkjetFile calls oConn.Open(ConnectionString) if oConn.State = 0. It manages its own connection lifecycle. The harness must set oConn (via Set oConn = CreateObject("ADODB.Connection")) and ConnectionString as globals before calling.ExportDirectory global: Used by ExportInkjetFile as-is (no trailing slash added internally). Must include trailing \ in the harness assignment.ExportInkjetFile creates its own internal Chilkat_9_5_0.Csv object. Chilkat unlock is process-wide — already done in harness init block. Read-back uses a separate object.| File | Purpose |
|---|---|
Tests/TrackingDataImport_TestHarness.vbs |
Target file — 3 insertion points: globals (after line 15), functionNames array (after line 31), init block (after line 69), test block (before line 206) |
ImportService/TrackingDataImport.vbs |
Source — ExportInkjetFile at line 251 (Function), GetSetting also in same file |
Data/webdata - Copy.mdb |
MDB fixture — real Kit + InkjetRecords + KitLabels + Colors + Jurisdiction + Contacts + Settings |
Data/webdata - Copy.mdb directly: It's already a copy and contains real data. No need to seed a new fixture. The UPDATE side effect (Kit.Status='Done’) is acceptable since this MDB is a disposable copy.SELECT TOP 1 ir.KitID FROM ((InkjetRecords ir INNER JOIN Kit k ON ir.KitID = k.ID) INNER JOIN Jurisdiction j ON k.JCode = j.JCode) INNER JOIN Contacts c ON k.JCode = c.JURISCODE to ensure discovered KitID has all required related records. Avoid orphan-crash on JurisdictionRs or ContactRs inside the function.fso.BuildPath(scriptDir, "export-test-output"). Delete before call (not just after) to ensure no stale CSV from a prior failed run contaminates assertions.Microsoft.ACE.OLEDB.12.0 first; fall back to Microsoft.Jet.OLEDB.4.0. If both fail, skip with message. Guard with fso.FileExists(integrationMdbPath) before attempting open.GetSetting and ExportInkjetFile in functionNames array — GetSetting is a DB-backed dependency called internally by ExportInkjetFile.verifyCsv.LoadFile(csvPath) return value and assert it before proceeding to column/row assertions — prevents vacuously-passing assertions on a failed load.fso.DeleteFolder in On Error Resume Next / On Error GoTo 0 — AV scanners may briefly hold a handle on the new CSV; a cleanup failure should not fail the test.Tests/TrackingDataImport_TestHarness.vbsDim declarations after line 15; insert ADODB probe block after line 69integrationDbAvailable/integrationDbSkipReason — same guard pattern as chilkatAvailableInsertion point: after line 15 (Dim DataDirectory). Add:
Dim oConn
Dim ConnectionString
Dim ExportDirectory
Dim integrationMdbPath
Dim integrationExportDir
Dim integrationDbAvailable
Dim integrationDbSkipReason
Insertion point: after line 69 (On Error GoTo 0 at end of Chilkat init block). Add ADODB probe block:
integrationMdbPath = fso.BuildPath(scriptDir, "..\Data\webdata - Copy.mdb")
integrationExportDir = fso.BuildPath(scriptDir, "export-test-output")
integrationDbAvailable = False
integrationDbSkipReason = ""
If Not fso.FileExists(integrationMdbPath) Then
integrationDbSkipReason = "MDB fixture not found: " & integrationMdbPath
Else
Set oConn = CreateObject("ADODB.Connection")
On Error Resume Next
oConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & integrationMdbPath & ";"
If Err.Number <> 0 Then
Err.Clear
oConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & integrationMdbPath & ";"
End If
If Err.Number <> 0 Then
integrationDbSkipReason = "No ADODB provider available (ACE and Jet both failed): " & Err.Description
Err.Clear
Else
integrationDbAvailable = True
ConnectionString = oConn.ConnectionString
ExportDirectory = integrationExportDir & "\"
End If
On Error GoTo 0
If oConn.State = 1 Then oConn.Close
End If
GetSetting and ExportInkjetFile to functionNames array
Tests/TrackingDataImport_TestHarness.vbsLoadFunctions call at line 34; order within array does not matterInsertion point: lines 30–31. Change:
"CheckStringDoesNotHaveForiegnCountries", _
"ValidImportCSV" _
To:
"CheckStringDoesNotHaveForiegnCountries", _
"ValidImportCSV", _
"GetSetting", _
"ExportInkjetFile" _
Tests/TrackingDataImport_TestHarness.vbsWScript.Echo "")chilkatAvailable AND integrationDbAvailable; uses AssertEqual throughout (no Assert sub exists); pre-call dir cleanup, post-call DB side-effect check, error-suppressed cleanupInsertion point: before line 206 (WScript.Echo ""). Add:
' === ExportInkjetFile Integration Test ===
If Not chilkatAvailable Then
WScript.Echo "SKIP: ExportInkjetFile integration test (Chilkat unavailable)"
ElseIf Not integrationDbAvailable Then
WScript.Echo "SKIP: ExportInkjetFile integration test (" & integrationDbSkipReason & ")"
Else
oConn.Open ConnectionString
Dim kitDiscoverRs
Set kitDiscoverRs = oConn.Execute( _
"SELECT TOP 1 ir.KitID FROM ((InkjetRecords ir " & _
"INNER JOIN Kit k ON ir.KitID = k.ID) " & _
"INNER JOIN Jurisdiction j ON k.JCode = j.JCode) " & _
"INNER JOIN Contacts c ON k.JCode = c.JURISCODE;")
If kitDiscoverRs.EOF Then
WScript.Echo "SKIP: ExportInkjetFile — no complete Kit+InkjetRecords+Jurisdiction+Contact found in fixture MDB"
oConn.Close
Else
Dim testKitID : testKitID = kitDiscoverRs("KitID").Value
Dim countRs
Set countRs = oConn.Execute("SELECT COUNT(*) AS N FROM InkjetRecords WHERE KitID=" & testKitID & ";")
Dim expectedRows : expectedRows = countRs("N").Value
Dim kitRsCheck
Set kitRsCheck = oConn.Execute("SELECT JCode FROM Kit WHERE ID=" & testKitID & ";")
Dim testJCode : testJCode = kitRsCheck("JCode").Value
oConn.Close
' Delete stale output before call, then recreate
On Error Resume Next
If fso.FolderExists(integrationExportDir) Then fso.DeleteFolder(integrationExportDir, True)
On Error GoTo 0
fso.CreateFolder integrationExportDir
ExportInkjetFile testKitID
Dim exportSubfolders : Set exportSubfolders = fso.GetFolder(integrationExportDir).SubFolders
Dim csvFound : csvFound = False
Dim csvPath : csvPath = ""
Dim sf
For Each sf In exportSubfolders
Dim csvFiles : Set csvFiles = sf.Files
Dim f
For Each f In csvFiles
If LCase(fso.GetExtensionName(f.Name)) = "csv" Then
csvFound = True
csvPath = f.Path
End If
Next
Next
AssertEqual csvFound, True, "[INT] ExportInkjetFile: CSV file created"
If csvFound Then
Dim verifyCsv : Set verifyCsv = CreateObject("Chilkat_9_5_0.Csv")
verifyCsv.HasColumnNames = 1
Dim csvLoaded : csvLoaded = verifyCsv.LoadFile(csvPath)
AssertEqual csvLoaded, True, "[INT] ExportInkjetFile: CSV loaded by Chilkat"
If csvLoaded Then
AssertEqual verifyCsv.NumColumns, 22, "[INT] ExportInkjetFile: 22 columns"
AssertEqual verifyCsv.ColumnName(0), "Full Name", "[INT] ExportInkjetFile: col 0 = Full Name"
AssertEqual verifyCsv.ColumnName(5), "IM barcode Characters", "[INT] ExportInkjetFile: col 5 = IM barcode Characters"
AssertEqual verifyCsv.ColumnName(8), "Ballot Number", "[INT] ExportInkjetFile: col 8 = Ballot Number"
AssertEqual verifyCsv.ColumnName(11), "Combined Pct_Ballot Num", "[INT] ExportInkjetFile: col 11 = Combined Pct_Ballot Num"
AssertEqual verifyCsv.ColumnName(19), "Matching Code", "[INT] ExportInkjetFile: col 19 = Matching Code"
AssertEqual verifyCsv.ColumnName(20), "ColorFilepath", "[INT] ExportInkjetFile: col 20 = ColorFilepath"
AssertEqual verifyCsv.ColumnName(21), "ColorName", "[INT] ExportInkjetFile: col 21 = ColorName"
AssertEqual verifyCsv.NumRows, expectedRows, "[INT] ExportInkjetFile: row count matches InkjetRecords"
Dim checkRows : checkRows = 10
If verifyCsv.NumRows < 10 Then checkRows = verifyCsv.NumRows
Dim r
For r = 0 To checkRows - 1
Dim ballotNum : ballotNum = verifyCsv.GetCell(r, 8)
AssertEqual (Left(ballotNum, 1) <> "0" Or ballotNum = ""), True, "[INT] ExportInkjetFile: row " & r & " Ballot Number no leading zeros"
Dim matchCode : matchCode = verifyCsv.GetCell(r, 19)
AssertEqual Left(matchCode, Len(testJCode)), testJCode, "[INT] ExportInkjetFile: row " & r & " Matching Code starts with JCode"
Next
End If
Set verifyCsv = Nothing
End If
oConn.Open ConnectionString
Dim sideEffectRs
Set sideEffectRs = oConn.Execute("SELECT Status, InkJetJob FROM Kit WHERE ID=" & testKitID & ";")
AssertEqual sideEffectRs("Status").Value, "Done", "[INT] ExportInkjetFile: Kit.Status = Done"
AssertEqual sideEffectRs("InkJetJob").Value, 1, "[INT] ExportInkjetFile: Kit.InkJetJob = 1"
oConn.Close
On Error Resume Next
If fso.FolderExists(integrationExportDir) Then fso.DeleteFolder(integrationExportDir, True)
On Error GoTo 0
End If
End If
Option Explicit compliance
Tests/TrackingDataImport_TestHarness.vbsDim declarationDims in Task 3: kitDiscoverRs, testKitID, countRs, expectedRows, kitRsCheck, testJCode, exportSubfolders, csvFound, csvPath, sf, csvFiles, f, verifyCsv, csvLoaded, checkRows, r, ballotNum, matchCode, sideEffectRs — all must be presentAC 1: Given Chilkat is available and Data/webdata - Copy.mdb contains a Kit with InkjetRecords, Jurisdiction, and Contact, when the harness calls ExportInkjetFile(testKitID), then a CSV file is created under Tests/export-test-output/<JobNumber>-<Name>/, it has exactly 22 columns with correct header names at indices 0/5/8/11/19/20/21, row count matches the InkjetRecords count, the first 10 rows have no leading zeros in “Ballot Number”, the first 10 rows have “Matching Code” starting with JCode, and Kit.Status='Done’ + Kit.InkJetJob=1 in the MDB.
AC 2: Given Chilkat is unavailable, when the harness reaches the ExportInkjetFile block, then it prints SKIP: ExportInkjetFile integration test (Chilkat unavailable) and no test failures are recorded.
AC 3: Given Data/webdata - Copy.mdb is absent or neither ACE nor Jet ADODB driver is available, when the ADODB probe block runs during harness init, then integrationDbAvailable is False, the test block prints a SKIP message with the reason, and no test failures are recorded.
AC 4: Given the MDB contains no Kit with all required related records (InkjetRecords + Jurisdiction + Contacts), when the discovery JOIN query runs, then it prints SKIP: ExportInkjetFile — no complete Kit+InkjetRecords+Jurisdiction+Contact found in fixture MDB and no test failures are recorded.
AC 5: Given a prior test run left Tests/export-test-output/ behind (simulating a failed cleanup), when the integration test runs, then the stale folder is deleted before ExportInkjetFile is called and the test proceeds without contaminated assertions.
Chilkat_9_5_0.Csv COM — must be registered and unlocked (guarded by chilkatAvailable)Microsoft.ACE.OLEDB.12.0 or Microsoft.Jet.OLEDB.4.0 — must be available for ADODB to open the MDBData/webdata - Copy.mdb — must exist with real Kit + InkjetRecords + KitLabels + Colors + Jurisdiction + Contacts + Settings(ElectionDate)ADODB.Connection — available on any Windows machine with Office/Access driversIntegration test only — no unit-level testing is viable for this function without significant refactoring. The test confirms the full output pipeline from DB read → CSV write → DB update.
ExportInkjetFile function uses objFSO (not fso). The line Set objFSO = fso was added in a prior workflow pass and is already present in the harness."Combined Pct_Ballot Num" — this is as-written in the source (line 296).ColumnName(n) method on the read-back CSV object uses 0-based index.Microsoft.ACE.OLEDB.12.0), falls back to Jet (Microsoft.Jet.OLEDB.4.0). Bitness matters — 32-bit cscript requires 32-bit drivers. Sets integrationDbAvailable = True/False and integrationDbSkipReason.oConn to validate the connection string. ExportInkjetFile internally calls oConn.Open(ConnectionString) if State=0 — so close it before calling the function. Reopen after for the side-effect assertion.ExportInkjetFile when it accesses JurisdictionRs("Name") or ContactRs("Title").integrationExportDir is deleted before calling ExportInkjetFile (not just after) to prevent stale CSVs from prior failed runs contaminating assertions.Powered by TurnKey Linux.