🏡 index : quine-global-boneyard/electron-builder.git

import { readAsarJson } from "app-builder-lib/out/asar/asar"
import { walk } from "builder-util"
import { Arch, Platform } from "electron-builder"
import { outputFile } from "fs-extra"
import * as fs from "fs/promises"
import { load } from "js-yaml"
import * as path from "path"
import { assertThat } from "./fileAssert"
import { PackedContext } from "./packTester"
import { diff, WineManager } from "./wine"
import { ExpectStatic } from "vitest"

export async function expectUpdateMetadata(expect: ExpectStatic, context: PackedContext, arch: Arch = Arch.ia32, requireCodeSign: boolean = false): Promise<void> {
  const data = load(await fs.readFile(path.join(context.getResources(Platform.WINDOWS, arch), "app-update.yml"), "utf-8")) as any
  if (requireCodeSign) {
    expect(data.publisherName).toEqual(["Foo, Inc"])
    delete data.publisherName
  }

  expect(data).toMatchSnapshot()
}

export async function checkHelpers(expect: ExpectStatic, resourceDir: string, isPackElevateHelper: boolean) {
  const elevateHelperExecutable = path.join(resourceDir, "elevate.exe")
  if (isPackElevateHelper) {
    await assertThat(expect, elevateHelperExecutable).isFile()
  } else {
    await assertThat(expect, elevateHelperExecutable).doesNotExist()
  }
}

export async function doTest(
  expect: ExpectStatic,
  outDir: string,
  perUser: boolean,
  productFilename = "TestApp Setup",
  name = "TestApp",
  menuCategory: string | null = null,
  packElevateHelper = true
) {
  if (process.env.DO_WINE !== "true") {
    return Promise.resolve()
  }

  const wine = new WineManager()
  await wine.prepare()
  const driveC = path.join(wine.wineDir!, "drive_c")
  const driveCWindows = path.join(wine.wineDir!, "drive_c", "windows")
  const perUserTempDir = path.join(wine.userDir!, "Temp")
  const walkFilter = (it: string) => {
    return it !== driveCWindows && it !== perUserTempDir
  }

  function listFiles() {
    return walk(driveC, null, { consume: walkFilter })
  }

  let fsBefore = await listFiles()

  await wine.exec(path.join(outDir, `${productFilename} Setup 1.1.0.exe`), "/S")

  let instDir = perUser ? path.join(wine.userDir!, "Local Settings", "Application Data", "Programs") : path.join(driveC, "Program Files")
  if (menuCategory != null) {
    instDir = path.join(instDir, menuCategory)
  }

  const appAsar = path.join(instDir, name, "resources", "app.asar")
  expect(await readAsarJson(appAsar, "package.json")).toMatchObject({
    name,
  })

  if (!perUser) {
    let startMenuDir = path.join(driveC, "users", "Public", "Start Menu", "Programs")
    if (menuCategory != null) {
      startMenuDir = path.join(startMenuDir, menuCategory)
    }
    await assertThat(expect, path.join(startMenuDir, `${productFilename}.lnk`)).isFile()
  }

  if (packElevateHelper) {
    await assertThat(expect, path.join(instDir, name, "resources", "elevate.exe")).isFile()
  } else {
    await assertThat(expect, path.join(instDir, name, "resources", "elevate.exe")).doesNotExist()
  }

  let fsAfter = await listFiles()

  let fsChanges = diff(fsBefore, fsAfter, driveC)
  expect(fsChanges.added).toMatchSnapshot()
  expect(fsChanges.deleted).toEqual([])

  // run installer again to test uninstall
  const appDataFile = path.join(wine.userDir!, "Application Data", name, "doNotDeleteMe")
  await outputFile(appDataFile, "app data must be not removed")
  fsBefore = await listFiles()
  await wine.exec(path.join(outDir, `${productFilename} Setup 1.1.0.exe`), "/S")
  fsAfter = await listFiles()

  fsChanges = diff(fsBefore, fsAfter, driveC)
  expect(fsChanges.added).toEqual([])
  expect(fsChanges.deleted).toEqual([])

  await assertThat(expect, appDataFile).isFile()

  await wine.exec(path.join(outDir, `${productFilename} Setup 1.1.0.exe`), "/S", "--delete-app-data")
  await assertThat(expect, appDataFile).doesNotExist()
}