Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The font-size value, specified in a media query, is not updated when resizing an iFrame in MS Edge #52

Closed
chooie opened this issue Mar 30, 2018 · 22 comments

Comments

@chooie
Copy link

chooie commented Mar 30, 2018

Edit: Solved. Need to force a reflow after resizing the frame. See this comment. Quixote needs to be updated to do this automatically; see this comment.

Steps to Reproduce

You should just be able to checkout the repo and run ./tasks test:quick to see the issue in action

The failing test: https://github.com/chooie/incremental_it/blob/9a6b3220bc80f3cc7bac970312e8b1bfb5e1c454/src/application/client/content/_main_test.js#L86

A Workaround

https://github.com/chooie/incremental_it/blob/073279ebac9162f8db90373c58f69410b44148d7/src/application/client/content/_main_test.js#L86

@jamesshore
Copy link
Owner

jamesshore commented Mar 30, 2018

Thanks for the clear report, @chooie. I won't be able to work on this right away, so here's a few questions that will help me get a solution to you faster:

  1. If you run the failing test on its own and visually inspect the results, is the font size changed? (Also, does the test still fail when it's run on its own?)
  2. Does this occur on other browsers, or just MS Edge?
  3. What happens if you add a timeout to the test, like this?
   it("is even bigger on wider devices", function(done) {
      cssHelper.frame.resize(cssHelper.mediumDeviceWidth, 500);
      setTimeout(function() {
        console.log("new", cssHelper.fontSize(element));
        assert.equal(cssHelper.fontSize(element), "64px");
        done();
      }, 1000);
  });

Thanks!

@chooie
Copy link
Author

chooie commented Mar 30, 2018

Hi James, I can try out your suggestions in a few hours. For now, though, I can confirm:

  1. It only occurs on MS Edge ( Edge 16.16299.0 (Windows 10.0.0))
    https://github.com/chooie/incremental_it/blob/9a6b3220bc80f3cc7bac970312e8b1bfb5e1c454/src/build/config/tested_browsers.js

@chooie
Copy link
Author

chooie commented Mar 30, 2018

  1. The font size IS changed

screen shot 2018-03-30 at 16 55 38

>>>> ./tasks.sh test:quick
For more forgiving test settings, use 'loose=true'
Checking Node.js version: .
Linting JavaScript: ..
Testing CSS:
LOG: 'new', '64px'
.
Mobile Safari 11.0.0 (iOS 11.2.0): Executed 1 of 19 SUCCESS (0.378 secs / 0.013 secs)
Firefox 59.0.0 (Mac OS X 10.13.0) LOG: 'new', '64px'
.
Firefox 59.0.0 (Mac OS X 10.13.0): Executed 1 of 19 SUCCESS (0.17 secs / 0.008 secs)
Safari 11.0.3 (Mac OS X 10.13.3) LOG: 'new', '64px'
.
Safari 11.0.3 (Mac OS X 10.13.3): Executed 1 of 19 SUCCESS (0.728 secs / 0.031 secs)
Chrome Mobile 55.0.2883 (Android 7.1.1) LOG: 'new', '64px'
.
Chrome Mobile 55.0.2883 (Android 7.1.1): Executed 1 of 19 SUCCESS (1.154 secs / 0.032 secs)
Chrome 65.0.3325 (Mac OS X 10.13.3) LOG: 'new', '64px'
.
Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 1 of 19 SUCCESS (0.255 secs / 0.002 secs)
Edge 16.16299.0 (Windows 10.0.0) LOG: 'new', '32px'
Edge 16.16299.0 (Windows 10.0.0) CSS: Layout Header is even bigger on wider devices FAILED
	AssertionError: expected '64px', but got '32px'
	   at fail (base/src/application/node_modules/vendor/proclaim-2.0.0.js?134aa623677f1257f43553dc0e41e969cf8ab7b4:308:9)
	   at proclaim.strictEqual (base/src/application/node_modules/vendor/proclaim-2.0.0.js?134aa623677f1257f43553dc0e41e969cf8ab7b4:39:13)
	   at exports.equal (base/src/application/node_modules/_assert.js?602de502ab1173dbd3a908ae09566397a3bace8d:62:5)
	   at Anonymous function (base/src/application/client/content/_main_test.js?c5565b94a936da60620c4f337886a8de916d2ddc:89:7)
Edge 16.16299.0 (Windows 10.0.0): Executed 1 of 19 (1 FAILED) ERROR (0.792 secs / 0.003 secs)
jake aborted.
Error: Karma tests failed
    at api.fail (/Users/chooie/code/projects/incremental_it/node_modules/jake/lib/api.js:336:18)
    at /Users/chooie/code/projects/incremental_it/node_modules/simplebuild-karma/src/index.js:64:26
(See full trace by running task with --trace)

3)If I add a timeout, it doesn't resolve the issue:

h1.New code

  it.only("is even bigger on wider devices", function(done) {
      this.timeout(10000);
      cssHelper.frame.resize(cssHelper.mediumDeviceWidth, 500);
      setTimeout(function() {
        console.log("new", cssHelper.fontSize(element));
        assert.equal(cssHelper.fontSize(element), "64px");
        done();
      }, 1000);
    });

h1.Results

>>>> ./tasks.sh test:quick
For more forgiving test settings, use 'loose=true'
Checking Node.js version: .
Linting JavaScript: .
Testing CSS:
Mobile Safari 11.0.0 (iOS 11.2.0) LOG: 'new', '64px'
.
Mobile Safari 11.0.0 (iOS 11.2.0): Executed 1 of 19 SUCCESS (1.329 secs / 1.002 secs)
Firefox 59.0.0 (Mac OS X 10.13.0) LOG: 'new', '64px'
.
Firefox 59.0.0 (Mac OS X 10.13.0): Executed 1 of 19 SUCCESS (1.482 secs / 1.008 secs)
Chrome Mobile 55.0.2883 (Android 7.1.1) LOG: 'new', '64px'
.
Chrome Mobile 55.0.2883 (Android 7.1.1): Executed 1 of 19 SUCCESS (1.751 secs / 1.006 secs)
Safari 11.0.3 (Mac OS X 10.13.3) LOG: 'new', '64px'
.
Safari 11.0.3 (Mac OS X 10.13.3): Executed 1 of 19 SUCCESS (1.806 secs / 1.002 secs)
Chrome 65.0.3325 (Mac OS X 10.13.3) LOG: 'new', '64px'
.
Chrome 65.0.3325 (Mac OS X 10.13.3): Executed 1 of 19 SUCCESS (1.566 secs / 1.005 secs)
Edge 16.16299.0 (Windows 10.0.0) LOG: 'new', '32px'
Edge 16.16299.0 (Windows 10.0.0) CSS: Layout Header is even bigger on wider devices FAILED
	Error: AssertionError: expected '64px', but got '32px' (http://10.0.2.2:9876src/application/node_modules/vendor/proclaim-2.0.0.js:308)
Edge 16.16299.0 (Windows 10.0.0): Executed 1 of 19 (1 FAILED) ERROR (8.842 secs / NaN secs)
jake aborted.
Error: Karma tests failed
    at api.fail (/Users/chooie/code/projects/incremental_it/node_modules/jake/lib/api.js:336:18)
    at /Users/chooie/code/projects/incremental_it/node_modules/simplebuild-karma/src/index.js:64:26
(See full trace by running task with --trace)

@jamesshore
Copy link
Owner

Thanks for checking. Unfortunately, these are the worst ones to troubleshoot. It seems likely that there's a bug in MS Edge, because the CSS API we're using is very straightforward. :-b It may be related to the font caching gotcha mentioned in the readme. I'll poke around and see what I can discover. It may be a while before I can look at it, though.

@woldie
Copy link

woldie commented Apr 2, 2018 via email

@jamesshore
Copy link
Owner

I agree with @woldie's suggestion of a simplest-possible test case. We should be able to shrink the CSS down to not much more than the font-size and media declarations, and even simplify the assertion for a MS Edge bug report. Also, if at any point the code starts passing, that will be very informative for us in terms of documenting the issue and coming up with a work-around that's compatible with frame.resize().

@chooie's current code has this assertion:

 assert.equal(cssHelper.fontSize(element), "64px");

That can be changed to this for the purposes of a bug report:

var domElement = element.toDomElement();
var domFrame = cssHelper.frame.toDomElement();

var styles = domFrame.contentWindow.getComputedStyle(domElement);
var fontSize = styles.getPropertyValue("font-size");
assert.equal(fontSize, "64px");

It's possible we're doing something incorrect with the way we're setting up the frame, too--there's a lot of fiddly edge cases associated with that code. The best reproduction code would get rid of Quixote entirely, I think, and just do the frame setup and resize directly in the test.

@jamesshore
Copy link
Owner

jamesshore commented Apr 2, 2018

This gist could be a helpful starting point for making a repro test case. It has the code for defining a frame already inlined: https://gist.github.com/jamesshore/c09d071eb5b16b7645f2

The resize code is very simple and should also be easy to inline:

this._domElement.setAttribute("width", "" + width);
this._domElement.setAttribute("height", "" + height);

@chooie
Copy link
Author

chooie commented Apr 2, 2018

Thanks, folks. I'll have a look at this tonight and work on getting a minimal example going.

@chooie
Copy link
Author

chooie commented Apr 3, 2018

I can now confirm that this is probably a bug in MS Edge.

Open this file in it and it will demonstrate the issue in the console:

ms_edge_iframe_bug_demo.html

<html>
  <head>
    <title>MS Edge Bug Example</title>
  </head>
  <body>
    <p>
      The header in the iFrame displays fine. `getPropertyValue("font-size")`,
      however, is incorrect
    </p>
<script>
function demonstrateFontSizeBug() {
  let iFrame = makeIframeWithStylesAndContent();
  let iFrameDocument = iFrame.contentWindow.document;
  let headerElement = iFrameDocument.getElementById("header");

  // Default works fine
  let headerStyles = iFrame.contentWindow.getComputedStyle(headerElement);
  let fontSize = headerStyles.getPropertyValue("font-size");
  console.log("Expect '10px' and got: '" + fontSize + "'");

  // MS Edge doesn't play nice with media queries, all other test browsers do
  iFrame.style.width = "1000px";
  iFrame.style.height = "500px";

  headerStyles = iFrame.contentWindow.getComputedStyle(headerElement);
  fontSize = headerStyles.getPropertyValue("font-size");
  console.log("Expect '64px' and got: '" + fontSize + "'");
}

function makeIframeWithStylesAndContent() {
  let iframe = document.createElement("iframe");
  iframe.id = "my-iframe";
  let css = `
<style type="text/css">
  .header {
      font-size: 10px;
  }

  /* Media queries must come after the 'default' styles */
  @media screen and (min-width: 640px) {
    .header {
        font-size: 64px;
    }
  }
</style>
`;

  let headerText = `
<h1 id="header" class="header">Hello</h1>
`;
  document.body.appendChild(iframe);

  let iframeDocument = iframe.contentWindow.document;
  iframeDocument.write(`
${css}
${headerText}
`);

  return iframe;
}

demonstrateFontSizeBug();
</script>
  </body>
</html>

Thank you for your help (and Quixote for finding this issue!). I'll file a bug report with the Edge devs.

@chooie
Copy link
Author

chooie commented Apr 3, 2018

@chooie
Copy link
Author

chooie commented Apr 3, 2018

Update: Putting the call to getComputedStyle in a setTimeout gives the correct value:

setTimeout(function() {
    headerStyles = iFrame.contentWindow.getComputedStyle(headerElement);
    fontSize = headerStyles.getPropertyValue("font-size");
    console.log("Expect '64px' and got: '" + fontSize + "'");
}, 0);

Would a workaround like this work for Quixote?

@woldie
Copy link

woldie commented Apr 3, 2018 via email

@jamesshore
Copy link
Owner

Interesting that setTimeout works for your test case but not when you tried it in this comment.

I'm going to leave this issue open for now as something to investigate further. At the very least, Quixote can provide a browser detect for this issue.

@chooie
Copy link
Author

chooie commented Apr 5, 2018

Hmm, I tried it out again with the original code and it's working now (with the timeout 'hack'). Either I didn't save the file or it was an extraneous mistake. For now, this workaround works for me! I'll follow up if something better turns up.

@chooie
Copy link
Author

chooie commented Apr 5, 2018

Looks like it's a flaky test from the race condition introduced by Edge. For integration tests, the problem is particularly prevalent (just on Edge) if the timeout is set to 0.

@jamesshore
Copy link
Owner

jamesshore commented Apr 6, 2018

Sometimes it's helpful to force a browser reflow. This will do it:

domElement.offsetHeight;

Does that help in this case?

@chooie
Copy link
Author

chooie commented Apr 10, 2018

It works and brings back synchronicity! Thanks, James. This is the best workaround so far.

function forceBrowserReflow() {
  document.body.offsetHeight;
}

@jamesshore
Copy link
Owner

Glad to hear it! I encountered a similar problem when adding a class to an element. I don't remember which browser was affected, but I had to force a reflow before the class took effect. It makes sense that resizing the frame could have the same kind of issue.

I think the best fix for this would be to modify frame.resize to force reflow after resizing. That should solve this problem universally. I'll leave this issue open until then.

@chooie
Copy link
Author

chooie commented Apr 10, 2018

Also, a quick correction:

function forceBrowserReflow(element) {
  element.offsetHeight;
}

I was experiencing another async issue with Firefox 59.0.0 (Mac OS X 10.13.0) when getting the font-size. Doing the reflow on the element under test, instead of the document, gets around this issue.

@jamesshore
Copy link
Owner

jamesshore commented Apr 9, 2020

I've successfully reproduced this issue with the following code in _q_frame_test.js (in the describe("instance") block, using the 0.14.1 version of the code):

		it("Issue #52", function() {
			frame.add(
				"<style type='text/css'>" +
					".header { font-size: 20px; }" +
					"@media (min-width: 640px) {" +
						".header { font-size: 40px; }" +
					"}" +
				"</style>"
			);
			var element = frame.add("<h1 class=header>hello</h1>");
			frame.resize(200, 500);
			assert.equal(element.getRawStyle("font-size"), "20px");

			frame.resize(800, 500);
			// var forceReflow = element.toDomElement().offsetHeight;
			assert.equal(element.getRawStyle("font-size"), "40px");
		});

As written, this test fails in these browsers:

  • IE 11.0.0 (Windows 7.0.0)
  • Edge 18.18362.0 (Windows 10.0.0)

It passes in these browsers:

  • Safari 13.1.0 (Mac OS X 10.14.6)
  • Firefox 75.0.0 (Mac OS X 10.14.0)
  • Mobile Safari 13.0.4 (iOS 13.3.0)
  • Chrome 80.0.3987 (Mac OS X 10.14.6)
  • Chrome Mobile 74.0.3729 (Android 0.0.0)

Uncommenting the forceReflow line makes it pass in all of these browsers. IE 8 wasn't tested; it can't handle the <style> tag.

@jamesshore
Copy link
Owner

A similar issue is present when using viewport-relative sizes. This one exists in all browsers tested except Firefox 75. (IE 8 doesn't support viewport-relative sizes.) The same fix works.

jamesshore added a commit that referenced this issue Apr 10, 2020
* dev:
  Update distribution files
  Tweak changelog
  Document reflow fix for 0.14.2 release
  Force reflow after resizing frame (fixes issue #52)
@jamesshore
Copy link
Owner

Fixed in v0.14.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants