Commit Graph

23 Commits

Author SHA1 Message Date
Yanzhen Yu
b26cb1a304 update test snapshot 2020-11-29 14:47:05 +08:00
yz-yu
55c5038528 Fix CI (#405)
* add yarn.lock to CI

* update travis config

* replace data url by placeholder in CI
2020-10-24 17:34:51 +08:00
Yanzhen Yu
7d5d003325 upgrade rrweb-snapshot 2020-10-24 16:36:06 +08:00
Eoghan Murray
665567119d Suspend mutations during snapshot (#385)
* The `processMutations` function needed to be bound to the `mutationBuffer` object, as otherwise `this` referred to the `MutationObserver` object itself

* Enable external pausing of mutation buffer emissions

 - no automatic pausing based on e.g. pageVisibility yet, assuming such a thing is desirable
   https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
 - user code has to call new API method `freezePage` e.g. when page is hidden or after a timeout
 - automatically unpauses when the next user initiated event occurs
   (am assuming everything that isn't a mutation event counts as 'user initiated'
   either way think this is the correct thing to do until I see a counterexample
   of an event that shouldn't cause the mutations to be unbufferred)

* Avoid a build up of duplicate `adds` by delaying pushing to adds until emission time

* Need to export freezePage in order to use it from rrweb.min.js

* Add a test to check if mutations can be turned off with the `freezePage` method

* I noticed out of order ids (in terms of a DOM walk) in a FullSnapshot.  A DOM mutation was executed against the mirror asynchronously before it could be fully processed. This would lead to a situation in replay where a mutation is executed against a DOM tree that already has the mutation applied. This changeset fixes that by freezing any mutations until the snapshot is completed.

* Remove attribute modifications from a mutation event that were incorrect in that they were repeating the attributes of those nodes present in the 'adds' array of the same mutation

* I've manually verified that this empty text node is actually removed when the dropdown is opened:

document.getElementById('select2-results-1').childNodes
NodeList(2) [li.select2-results-dept-0.select2-result.select2-result-selectable.select2-highlighted, li.select2-results-dept-0.select2-result.select2-result-selectable]

and also that it is not reinstated after the second `await page.click('.select2-container');`

* Rearrange when removal happens in order to satisfy tests. I'm also reverting a recent test change (2600fe7) so that tests pass after this rearrangement; I believe that test change to still be the correct way of doing it, but maybe it is not strictly important that there are extra mutations on attributes of just added nodes

* As mutations are now paused during FullSnapshots, we shouldn't be counting this as a 'user emission'. We automatically emit mutations after unpause anyway ('emit anything queued up now')

* Ensure that we clear arrays before emitting, as the mutation could have the side effect of triggering a FullSnapshot (checkoutEveryNth), which would otherwise re-trigger emission of same mutation (through the new pause/fullsnapshot/mutationemit/unpause process)

* Don't let the programattic pausing during TakeFullSnapshot accidentally unpause a manual call to the API method `freezePage`

* Rename paused -> frozen for consistency and change to use getter/setter access methods
2020-10-04 20:54:10 +08:00
yz-yu
772c0e021a record canvas mutations (#296)
* record canvas mutations

close #60, #261

This patch implements the canvas mutation observer.
It consists of both the record and the replay side changes.

In the record side, we add a `recordCanvas` flag to indicate
whether to record canvas elements and the flag defaults to false.
Different from our other observers, the canvas observer was
disabled by default. Because some applications with heavy canvas
usage may emit a lot of data as canvas changed, especially the
scenarios that use a lot of `drawImage` API.
So the behavior should be audited by users and only record canvas
when the flag was set to true.

In the replay side, we add a `UNSAFE_replayCanvas` flag to indicate
whether to replay canvas mutations.
Similar to the `recordCanvas` flag, `UNSAFE_replayCanvas` defaults
to false. But unlike the record canvas implementation is stable and
safe, the replay canvas implementation is UNSAFE.
It's unsafe because we need to add `allow-scripts` to the replay
sandbox, which may cause some unexpected script execution. Currently,
users should be aware of this implementation detail and enable this
feature carefully.

* update canvas integration test
2020-08-22 16:44:02 +08:00
yz-yu
5d83ee39fd close #280. Improve the performance of the DOM mutation observer. (#284)
This issue was originally reported in #280 but may also relate
to #167 and other potential performance issues in the recording.

In #206 I implemented the new mutation observer which will defer
the serialization of DOM, which helps us to have a consistent DOM
order for the replay.

In this implementation, we use an array to represent the `addQueue`.
Whenever we need to consume the queue, we will iterate it to make
sure there is no dead loop, and then shift the first item to see
whether it can be serialized at the new timing.

But this implementation may be very slow when there are a lot of newly
added DOM since it will do an O(n^2) iteration.

For example, if we have three newly added DOM `n1`, `n2`, `n3`,
the iteration looks like this:
```
[n1, n2, n3]
	n1 -> n2 -> n3, consume n3
[n1, n2]
	n1 -> n2, consume n2
[n1]
	n1, consume n1
```
We should have a better performance if te iteration looks like this:
```
[n1, n2, n3]
	n3, consume n3
[n1, n2]
	n2, consume n2
[n1]
	n1, consume n1
```

Simply reverse the mutation payload does not work, because it does
not always as same as the DOM order.

So in this patch, we replace the `addQueue` with a double linked list,
which can:
1. represent the DOM order in its data structure
2. has an O(1) time complexity when looking up the sibling of a list item
3. has an O(1) time complexity when removing a list item
2020-08-16 14:47:25 +08:00
yz-yu
7de7eb5e54 mask input options and sampling options (#252)
* part of #80, support mask input options

* close #188 enhance sampling options
Use a more general sampling strategy interface to describe the
configuration of sampling events collection.

Implemented mousmove, mouse interaction, scroll and input sampling
strategy.
2020-07-18 15:05:19 +08:00
yz-yu
7a666293b6 mutation observer v2 (#206)
There are some long-term issues in rrweb's mutation observer.

A scenario cause problem:
A list of DOM node: n1, n2, n3, n4, n5
Steps of modifying the nodes:
  1. remove n1, n2, n3, n4 sequentially
  2. append n4, n3, n2, n1 after n5 sequentially
Then we got the added node data like this:
  (id: n4, prev: null, next: n3  )
  (id: n3, prev: n4,   next: n2  )
  (id: n2, prev: n3,   next: n1  )
  (id: n1, prev: n2,   next: null)
The problem comes when we try to replay the first add node datum.
Since its prev node is null, we rely on its next sibling n3. But
n3 was not present at this moment, and in previous code, we fallback
to append n4 to the last of its parent node.

The solution is to defer the append of elements that missing
siblings. But it is also hard to tell which node is the first one
that needs to be appended.

Take a step back and rethink the design of the mutation observer,
we've found there are two implementations make things complicated.
1. We set the id to -1 when we seeing some nodes are not serialized yet.
2. We record both previous sibling and next sibling to determine the
position of the node.
But we can do better!
First, we can put nodes with un-serialized siblings
to a queue, and try to add it again later. Then we can just record the next
sibling as 'the single truth' so we can be sure which node is the last
one of its parent.

This patch has implemented the new observer strategy. Data recorded with
the new observer should no longer have any node with id -1. But for
compatibility consideration, we still keep some replayer code that helps
solve legacy data.
2020-05-02 14:08:10 +08:00
Yanzhen Yu
36ba02e709 use a fixed version of styled-components to make snapshot testing stable 2020-04-11 22:51:50 +08:00
Yanzhen Yu
02a33faaf9 add an integration tests for react and styled components 2020-03-21 23:21:45 +08:00
Yanzhen Yu
5e549c4ee4 make the unit tests more stable 2020-03-21 22:18:08 +08:00
David Cramer
046936b3e8 Add observers for stylesheet mutations (#177)
* hack together stylesheet observer

* Add test coverage for insertRule/deleteRule on stylesheets

* Add new observers

* update patch based on changes to master

* Functioning event recording

* Remove print statements

* Fix ID usage and mark add vs remove

* Correct type

Co-authored-by: Jon Perl <perl.jonathan@gmail.com>
2020-02-22 12:59:55 +08:00
Yanzhen Yu
c00c4ad646 update mask option test snapshot 2019-08-12 21:24:47 +08:00
Sebastian Jakob
189df87b9d Option to mask inputs (#80)
* Option to mask inputs

Added option 'maskAllInputs' to replace all user inputs with an Asterisk.

* Update types.d.ts
2019-06-15 12:52:08 +08:00
Yanzhen Yu
6d3b9c2345 Upgrade the DOM mutation observer
This is an important patch contains some crtical bug fixes for
the DOM mutation observer.
Previously the observer did not handle complex DOM movement very
well. So in this patch we optimized this by distinguishing moved
node better and added a resolving queue to avoid the error caused
by ordering.
2019-06-05 16:39:29 +08:00
Yanzhen Yu
dcc7b925fe fix character data test snapshot with latest puppeteer 2019-04-05 14:20:01 +08:00
Yanzhen Yu
406e7a8d39 update mutation observer handler
1. deep delete from adds set when node was dropped
2. remove node from dropped set when node was added again
2019-02-03 23:07:35 +08:00
yz-yu
3daedfa284 fix remove node observer and check on the result of getNode (#43)
* check removed node and its parent before collect

* add more more checks on the result of getNode
2019-01-21 19:18:51 +08:00
yz-yu
cedc87c69e add checkout config to recorder (#36)
* add checkout config to recorder

* add test cases for checkout feature and extract assertSnapshot method
2019-01-11 10:52:04 +08:00
Yanzhen Yu
8f24cb78b3 fix block strategy
If an element was blocked, its child nodes should also be blocked.
The interactions and mutations on the element and its child nodes
also need to be blocked.
2018-12-30 21:46:23 +08:00
Yanzhen Yu
2c9db926c0 resolve #1 add ignore and block strategy for privacy purpose 2018-12-02 23:23:21 +08:00
Yanzhen Yu
40e030eda1 ignore href in integration test to avoid fail when code changed 2018-11-14 14:25:11 +08:00
Yanzhen Yu
4a7e1e70c6 update test command 2018-11-13 16:26:11 +08:00