question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

File's instanceof File is false. Two windows have different File classes.

See original GitHub issue
  • Operating System: Windows 7
  • Cypress Version: 1.0.3
  • Browser Version: Chrome 62

Is this a Feature or Bug?

Bug

Current behavior:

File class is not shared with window’s children.

Desired behavior:

File class is somehow shared.

How to reproduce:

  1. Write test and create a file in it.
  2. Use created file in app code (instanceof File)

Test code:

describe('Create new File', function() {
  it('should has same File class', function() {
    const file = new File(/* arguments */);
    console.log(file instanceof File); // true
    
    // test runs in new window with different File
    doSomethingWithFile(file); // false
  });
});
// App code
const doSomethingWithFile = file => console.log(file instanceof File);

Additional Info (images, stack traces, etc)

Where did I encounter a problem: https://github.com/jaydenseric/extract-files/blob/10236ac78548a3f9c64d148aa79e1444e8dff285/src/index.js#L33

Object.prototype.toString.call(node[key]) === "[object File]" // works

SO topic: https://stackoverflow.com/questions/30040096/a-file-object-in-chrome-passed-between-windows-is-no-longer-an-instanceof-file

Temporary hack

// vendor/extract-files/index.js

// https://github.com/jaydenseric/extract-files/blob/master/src/index.js
// https://github.com/cypress-io/cypress/issues/933
/**
 * Checks a node is an enumerable object.
 * @param {*} node - A node to check.
 * @returns {Boolean} Is the node an enumerable object.
 */
export const isObject = node => typeof node === 'object' && node !== null

/**
 * A file extraction.
 * @typedef {Object} ExtractedFile
 * @property {String} path - Original location in the object tree.
 * @property {String} file - The actual file.
 */

/**
 * Reversibly extracts files from an object tree.
 * @param {object} tree - An object tree to extract files from.
 * @param {string} [treePath=''] - Optional tree path to prefix file paths.
 * @returns {ExtractedFile[]} Extracted files.
 */
export function extractFiles(tree, treePath = '') {
  const files = []
  const recurse = (node, nodePath) => {
    // Iterate enumerable properties of the node
    Object.keys(node).forEach(key => {
      // Skip non-object
      if (!isObject(node[key])) return

      const path = `${nodePath}${key}`

      if (
        // Node is a File
      (typeof File !== 'undefined' &&
        Object.prototype.toString.call(node[key]) === '[object File]') ||
      // Node is a ReactNativeFile
      node[key] instanceof ReactNativeFile
      ) {
        // Extract the file and it's object tree path
        files.push({ path, file: node[key] })

        // Delete the file. Array items must be deleted without reindexing to
        // allow repopulation in a reverse operation.
        delete node[key]

        // No further checks or recursion
        return
      }

      if (typeof FileList !== 'undefined' && node[key] instanceof FileList)
      // Convert read-only FileList to an array for manipulation
        node[key] = Array.from(node[key])

      // Recurse into child node
      recurse(node[key], `${path}.`)
    })
  }

  if (isObject(tree))
  // Recurse object tree
    recurse(
      tree,
      // If a tree path was provided, append a dot
      treePath === '' ? treePath : `${treePath}.`
    )

  return files
}

/**
 * A React Native FormData file object.
 * @see {@link https://github.com/facebook/react-native/blob/v0.45.1/Libraries/Network/FormData.js#L34}
 * @typedef {Object} ReactNativeFileObject
 * @property {String} uri - File system path.
 * @property {String} [type] - File content type.
 * @property {String} [name] - File name.
 */

/**
 * A React Native file.
 */
export class ReactNativeFile {
  /**
   * Constructs a new file.
   * @param {ReactNativeFileObject} file
   * @example
   * const file = new ReactNativeFile({
   *  uri: uriFromCameraRoll,
   *  type: 'image/jpeg',
   *  name: 'photo.jpg'
   * })
   */
  constructor({ uri, type, name }) {
    this.uri = uri
    this.type = type
    this.name = name
  }

  /**
   * Creates an array of file instances.
   * @param {ReactNativeFileObject[]} files
   * @example
   * const files = ReactNativeFile.list([{
   *   uri: uriFromCameraRoll1,
   *   type: 'image/jpeg',
   *   name: 'photo-1.jpg'
   * }, {
   *   uri: uriFromCameraRoll2,
   *   type: 'image/jpeg',
   *   name: 'photo-2.jpg'
   * }])
   */
  static list = files => files.map(file => new ReactNativeFile(file))
}
// package.json (this works only for yarn)

"resolutions": {
  "apollo-upload-client/extract-files": "file:./vendor/extract-files"
}
// webpack.config.js

module: {
  rules: [
    {
      test: /\.(js|jsx|mjs)$/,
      include: [
        path.resolve(__dirname, '../node_modules/extract-files'),
        // ...
      ],
    }
  ]
}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

11reactions
brian-manncommented, Nov 20, 2017

This should be fairly simple to fix: you simply need to instantiate Files from your application’s window, and not from the test spec window.

// nope
// this is using the global window in the test spec
new File() 

cy.window().then((win) => {
  // yup
  // this is using the File constructor from the application window
  new win.File()
})
0reactions
jennifer-shehanecommented, Jun 16, 2021

@tnrich I agree, this would be great. You can express your interest in this feature here: https://github.com/cypress-io/cypress/issues/170

Read more comments on GitHub >

github_iconTop Results From Across the Web

A File object in Chrome passed between windows is no longer ...
You're checking against the wrong File class. Since each window has its own scope, you need files[0] instanceof opener.File.
Read more >
Chapter 4. The class File Format - Oracle Help Center
A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit quantities are constructed by reading in two, four,...
Read more >
Class.isInstance vs Class.isAssignableFrom and instanceof
In this quick tutorial, we're going to take a look at the difference between instanceof, Class.isInstance, and Class.isAssignableFrom.
Read more >
Type Operators - Manual - PHP
instanceof is used to determine whether a PHP variable is an instantiated object of a certain class: Example #1 Using instanceof with classes....
Read more >
jdk8/jdk8/jdk: 687fd7c7986d src/share/classes/java/io/File.java
The file * system may have multiple sets of access permissions on a single ... and classes for the Java virtual machine to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found