-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Bump top-level matchers api to upper Detox layer (where they should be) #2214
Conversation
ad7a4ba
to
0686834
Compare
How does it relate to #2012? |
@rotemmiz, Amit wants to create a convenient DSL for taking element screenshots. He'll explain in depth if you want, but anyway I think that's the right direction. |
0686834
to
61e19cb
Compare
@rotemmiz I'll write down an elaborate explanation asap! |
Pull Request Test Coverage Report for Build 2456
💛 - Coveralls |
I am still not convinced that this is an important change, though I am OK with whatever makes you happy :) The API you mentioned |
@@ -111,6 +111,11 @@ describe('Device', () => { | |||
expect(device.name).toEqual('mock-device-name-from-driver'); | |||
}); | |||
|
|||
it('should return the type from the configuration', async () => { | |||
const device = validDevice(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d4vidi, just so I don't forget. How well does that .type
implementation play with our recently added 3rd party device driver support? That is, where you can point Detox to JS module path with a custom driver implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. With this implementation it will return the relative-path as-is, which might be weird, but that wouldn't be the driver's fault (rather, the whole concept's "fault"). This is why I suggest to keep as-is. Nevertheless, it is overrideable by the driver's implementor.
this._artifactsManager = new ArtifactsManager(this._artifactsConfig); | ||
this._artifactsManager.subscribeToDeviceEvents(this._eventEmitter); | ||
this._artifactsManager.registerArtifactPlugins(deviceDriver.declareArtifactPlugins()); | ||
|
||
await this.device.prepare(); | ||
|
||
const matchers = matchersRegistry.resolve(this.device, { | ||
invocationManager, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@d4vidi, so, your plan is to inject device
or a similar handle there, to ensure that the matchers will be able to pull the files from the device, after the screenshot is done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bingo! The restored flexibility would allow us to do so 💪
It can be defined and worked out to take the screenshot on the device, as you normally would, such that a a file will be created on the device (part A of my so-called pseudo-code). But it would not be able to pull the file back to the host, as it cannot access the
|
61e19cb
to
5e69e58
Compare
Description
Relates to #2012: lays some preliminary ground work so that we could introduce it with proper API.
Dive-in
Looking at the current software architecture of Detox at a high-level perspective, we see two main distinct units, top-to-bottom:
expect
and element-interactions as a top-level, user-facing API (e.g.element(by.id(testId)).tap()
), which in turn uses a distinct, platform-specific node-side (JS) implementation that eventually directly triggers device-side logic usinginvoke
.device.takeScreenshot()
), which are provided mainly by the (currently) singletonDevice
object, that in turns delegates platform-specific logic to Drivers.While the two global units are, in principle, agnostic, we've nevertheless created an artificial coupling between them, as the top-level implementation of unit 1 is created via the drivers of unit 2, due to convenience (example). Unfortunately, this type of an unnecessary coupling - as a rule of thumb, damages flexibility, and we can see it in the case of elements' screenshot.
The pseudo-code implementation of taking an element screenshot is as follows:
a.
Invoke
an on-test-device, native method that creates an on-device.png
file.b. Pull the image back to the host through the driver (e.g. using
adb
) and provide the path back to the caller.Ideally, this top-level API for doing this would be amazing:
But due to the coupling mentioned earlier, this cannot be done, as the underlying
Element.takeScreenshot()
function that would implement this -- originally generated by driver, cannot access thedevice
in part b of the pseudo-code (!) It more so artificially forces us onto this kind of an API, which is largely undesired as it is both not friendly and would encourage code duplication and single-responsibility breakage in Detox itself:If we want to nevertheless stick to the API that we really want - and with that, empower high flexibility in Detox (yes, gimme all those things!), we need to break the coupling.
This is the scope of this PR: 100% Separating drivers and matchers, and their creation. Instead of having the matchers created by the drivers, we delegate the proper matcher resolution to a new util called
matchersRegistry
(equilvant todriverRegistry
), which is utilized in the Detox class (aka our Detox main layer).Unfortunately, the main drawback is a minor breakage of external-drivers implementation: Whichever plugin-driver implementations that exist out there in the wild -- they still provide the matchers through the driver. Fortunately, I've made the migration pretty easy. Given a plugin
driver.js
, users will have to apply these minor changes: