thebrowsercompany / swift-webdriver

A Swift library for communicating with WebDriver (Appium/WinAppDriver) endpoints
BSD 3-Clause "New" or "Revised" License
99 stars 3 forks source link

Build an app to write tests against #110

Open tristanlabelle opened 10 months ago

tristanlabelle commented 10 months ago

We could easily build a Swift version of this app which pops a system standard file open dialog. That should give us a well-known, stable(ish) UI to write tests against.

int main() {
    OPENFILENAMEW openFileName = {};
    openFileName.lStructSize = sizeof(OPENFILENAMEW);
    wchar_t filePath[256] = {};
    filePath[0] = 0;
    openFileName.lpstrFile = filePath;
    openFileName.nMaxFile = 256;
    GetOpenFileNameW(&openFileName);
}
Squidonomics commented 9 months ago

Something like:

func main() {
    let openFileWindow = NSOpenPanel()
    openFileWindow.allowsMultipleSelection = false
    openFileWindow.canChooseDirectories = false

    if openFileWindow.runModal() == .OK {
        guard let selectedFileURL = openFileWindow.url else {
            return
        }

        let filePath = selectedFileURL.path
        print("Selected file path: \(filePath)")
    }
}
tristanlabelle commented 9 months ago

@Squidonomics NSOpenPanel is part of AppKit, which is macOS-specific. We can translate the C++ code above to Swift pretty much directly by using the WinSDK module on Windows, which should expose GetOpenFileNameW.

Squidonomics commented 9 months ago

@tristanlabelle Ah more like this then?

import WinSDK

func main() {
    var openFileWindow = openFileWindowW()
    openFileWindow.lStructSize = UInt32(sizeof(openFileWindowW.self))
    var filePath: [WCHAR] = Array(repeating: 0, count: 256)
    openFileWindow.lpstrFile = &filePath
    openFileWindow.nMaxFile = 256

    if GetOpenFileNameW(&openFileWindow) != 0 {
        guard let selectedFilePath = String(bytes: filePath, encoding: .unicode) else {
            return
        }
        print("Selected file path: \(selectedFilePath)")
    } else {
        print("Error: Failed to open file selection dialog.")
    }
}
compnerd commented 9 months ago

Note that the use of the array that way is technically UB. This needs a tad bit more work to create the window and all, but should be mostly correct.

import WinSDK

internal var OFN_PATHMUSTEXIST: DWORD {
  DWORD(WinSDK.OFN_PATHMUSTEXIST)
}
internal var OFN_FILEMUSTEXIST: DWORD {
  DWORD(WinSDK.OFN_FILEMUSTEXIST)
}
internal var GENERIC_READ: DWORD {
  DWORD(WinSDK.GENERIC_READ)
}
internal var OPEN_EXISTING: DWORD {
  DWORD(WinSDK.OPEN_EXISTING)
}
internal var FILE_ATTRIBUTE_NORMAL: DWORD {
  DWORD(WinSDK.FILE_ATTRIBUTE_NORMAL)
}

var ofn: OPENFILENAMEW = .init()
ofn.lStructSize = DWORD(MemoryLayout<OPENFILENAMEW>.size)
ofn.hwndOwner = ...
let hFile: HANDLE = withUnsafeTemporaryStorage(of: WCHAR.self, capacity: Int(MAX_PATH)) {
  ofn.lpstrFile = $0.baseAddress
  ofn.lpstrFile[0] = '\0'
  ofn.nMaxFile = $0.count
  ofn.lpstrFileTitle = nil
  ofn.nMaxFileTitle = 0
  ofn.lpstrInitialDir = nil
  ofn.Flags = OFN_PATHMUSTEXIT | OFN_FILEMUSTEXIST
  return "All\0.*\0Text\0*.TXT\0".withCString(encodedAs: UTF16.self) {
    ofn.lpstrFilter = $0
    ofn.nFilterIndex = 1
    guard GetOpenFileName(&ofn) else { return INVALID_HANDLE }
    return CreateFileW(ofn.lpstrFile, GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nil)
  }
}