swift-snapshot-testing: File Save Permissions Error

Hi 👋

First off just wanted to say thanks for the project, it’s been a breeze to setup and super refreshing! – Good work!

My question is currently whether or not this library is suppose to support physical devices or if the intended use is limited to Simulators?

When running on a physical device I get the below error when fileManager.createDirectory is called. The same is not true when ran from a simulator (which works as expected, without errors).

Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “CaseNameTests” in the folder “__Snapshots__”." UserInfo={NSFilePath=/Users/name/path/to/repo/ModuleTests/__Snapshots__/CaseNameTests, NSUnderlyingError=0x1c28585d0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

This appears to be the same issue referenced here

Thanks in advance 😄

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 18 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Hi @BenoitCaron and @fabstu , I ran into the same issue on macOS. What solved it for me was to convert the URL to string with .path() instead of ..absoluteString() in my custom myAssertSnapshot, like so

let snapshotDirectory = createSnapshotDirectory(file: file) // returns URL

let failure = verifySnapshot(
      matching: value,
      as: snapshotting,
      named: name,
      record: recording,
      snapshotDirectory: snapshotDirectory.path,
      timeout: timeout,
      file: file,
      testName: testName,
      line: line
    )

I am having same issue as others described for iOS device. I wanted to check real device, because for some reason code coverage is not gathered on simulator. It is gathered just fine for physical device, but I am getting failed - You don’t have permission to save the file “CalendarLargeWidgetViewSnapshotTests” in the folder “__Snapshots__”. failure in tests 😃

I fixed this by selecting Expand Variables Based On and selecting the based Target. It fixed for me.

Screen Shot 2021-11-11 at 18 14 14

No problem! More than happy to try and explain our use case a bit more,

Internally we have a CI platform that supports a large number of physical devices ranging from phones through tablets of varying sizes and configurations. We take advantage of Hive CI to run our integration tests on and were hoping to also take advantage of it for our snapshot tests too.

In general this comes down to a bit of reassurance from our testing department as we have seen various little differences in the past when it comes to Simulator vs Physical Device and was hoping to do the comparison on the closest thing to real world as possible

Hope that makes sense?

Hi @stephencelis,

I tried writing my own assertSnapshot in order to change the output directory, and my error is similar, but not exactly the same: failed - You can’t save the file “MyTests” because the volume is read only.

I tried replicating the default behaviour, but the error still occurs.

public func snapshotDirectory(file: StaticString) -> String {
    let fileUrl = URL(fileURLWithPath: "\(file)", isDirectory: false)
    let fileName = fileUrl.deletingPathExtension().lastPathComponent

    return fileUrl.deletingLastPathComponent()
        .appendingPathComponent("__Snapshots__")
        .appendingPathComponent(fileName)
        .absoluteString
 }

public func myAssertSnapshot<Value, Format>(
    matching value: @autoclosure () throws -> Value,
    as snapshotting: Snapshotting<Value, Format>,
    named name: String? = nil,
    record recording: Bool = false,
    timeout: TimeInterval = 5,
    file: StaticString = #file,
    testName: String = #function,
    line: UInt = #line
) {
    let failure = try verifySnapshot(
        matching: value(),
        as: snapshotting,
        named: name,
        record: recording,
        snapshotDirectory: snapshotDirectory(file: file),
        timeout: timeout,
        file: file,
        testName: testName
    )
    guard let message = failure else { return }
    XCTFail(message, file: file, line: line)
}

This is the default code, in AssertSnapshot.swift:

      let fileUrl = URL(fileURLWithPath: "\(file)", isDirectory: false)
      let fileName = fileUrl.deletingPathExtension().lastPathComponent

      let snapshotDirectoryUrl = snapshotDirectory.map { URL(fileURLWithPath: $0, isDirectory: true) }
        ?? fileUrl
          .deletingLastPathComponent()
          .appendingPathComponent("__Snapshots__")
          .appendingPathComponent(fileName)

It seems snapshotDirectory.map { URL(fileURLWithPath: $0, isDirectory: true) } and fileUrl.deletingLastPathComponent().appendingPathComponent("__Snapshots__").appendingPathComponent(fileName) don’t output the exact same thing:

  • snapshotDirectory.map { URL(fileURLWithPath: $0, isDirectory: true) } outputs file:/Users/benoit/myApp/myApp-iOSTests/__Snapshots__/MyTests/ -- file:///
    • this one doesn’t work
  • fileUrl.deletingLastPathComponent().appendingPathComponent("__Snapshots__").appendingPathComponent(fileName) outputs file:///Users/benoit/myApp/myApp-iOSTests/__Snapshots__/MyTests/
    • this one works

Why is there a difference? Am I missing something?

Edit: I forked the library and replaced the String? snapshotDirectory parameter with a URL? snapshotDirectory parameter, and it does work as intended. Should I create a PR?

I’m running into this error while trying to see snapshots to disk in a macOS test environment. Is there an extra set of config for Mac testing?