[FIX] Codepush: unset 'useAccessibilityLabel' and 'actionNameAttribute' properties#890
Conversation
47fb8ca to
96f50cf
Compare
Datadog ReportBranch report: ✅ 0 Failed, 663 Passed, 1 Skipped, 3.75s Total Time |
| const partialConfiguration: RequiredOrDiscard<AutoInstrumentationConfiguration> = { | ||
| trackErrors: configuration.trackErrors, | ||
| trackResources: configuration.trackResources, | ||
| trackInteractions: configuration.trackInteractions, | ||
| firstPartyHosts: configuration.firstPartyHosts, | ||
| logEventMapper: configuration.logEventMapper, | ||
| errorEventMapper: configuration.errorEventMapper, | ||
| resourceEventMapper: configuration.resourceEventMapper, | ||
| actionEventMapper: configuration.actionEventMapper, | ||
| useAccessibilityLabel: configuration.useAccessibilityLabel, | ||
| resourceTracingSamplingRate: configuration.resourceTracingSamplingRate, | ||
| actionNameAttribute: | ||
| configuration.actionNameAttribute ?? DISCARD_PROPERTY | ||
| }; | ||
|
|
||
| return removeDiscardProperties( | ||
| partialConfiguration | ||
| ) as AutoInstrumentationConfiguration; |
There was a problem hiding this comment.
I'm having trouble understanding this, why not just make it partial ?
const partialConfiguration: Partial<AutoInstrumentationConfiguration> ?
or if you want some to be partial and others to be required, maybe doing something like this ?
const partialConfiguration: Partial<AutoInstrumentationConfiguration> & {trackInteractions: AutoInstrumentationConfiguration['trackInteractions']}
But the way we're doing the types here doesn't feel right.
There was a problem hiding this comment.
The problem with Partial is that you are going to miss certain properties, because TSC won't complain.
We can't directly assign each property of DatadogProviderConfiguration to the partial configuration, because we want to skip the extra ones.
If we use Required<AutoInstrumentationConfiguration>, optional properties like actionNameAttribute will require a non-undefined value, and will make TSC complain, which is also not good.
If we use Partial<AutoInstrumentationConfiguration>, and we don't explicitly add the properties if we introduce new ones in the future, we won't catch it with TSC. Partial should be used when certain properties can be skipped, but this is not the case. Optional properties still have to be mapped using the DatadogProviderConfiguration properties.
I know this does not feel right, but I honestly could not find a good alternative to type it in a way that would force developers to map all properties.
What does this PR do?
Fixes missing configuration properties
useAccessibilityLabelandactionNameAttribute.Overview of configuration handling
flowchart TD A(["**DatadogCodepushProvider**"]) --> B{"Is **DatadogProviderConfiguration** configuration? (*e.g FileBasedConfiguration*)"} B -- YES (EXPECTED USE-CASE) --> C["ASYNC INIT"] C --> E["(ASYNC) Wait for **CodePush version**"] E --> H["(ASYNC) Call **DatadogProvider.initialize** with full DatadogProviderConfiguration, containing credentials and version"] C --> F["(SYNC) Extract **partial configuration** from full configuration (**THE ISSUE IS HERE**)"] F --> I["(SYNC) Set up **auto-instrumentation** from **partial configuration**"] B -- NO (LOOSELY TYPED CONFIG)--> D["SYNC INIT"] D --> J["Renders **DatadogProvider** with **given configuration** (fallsback to non-codepush implementation)"]What is the issue?
When a
DatadogProviderConfigurationis passed, we manually extract a partialAutoInstrumentationConfigurationto initializeDatadogProviderin ASYNC mode (no events will be sent untilDatadogCodepushProvider.initializeis explicitly called in the future, when the CodePush version is retrieved).Here is how we do it:
There are two missing properties:
useAccessibilityLabelandactionNameAttribute.Solution
To avoid similar problems in the future, we now build the partial configuration with a custom function:
The custom
RequiredOrDiscardtype, defined as:forces you to explicitly set each property for the
AutoInstrumentationConfigurationobject. We need these special types, asRequired<T>would force every property to be non-optional, which does not fit our use-case, where some properties inDatadogProviderConfigurationcan be undefined (e.gactionNameAttribute)For this reason we temporarily use
DISCARD_PROPERTYas the default value for undefined configuration properties, and remove them right after.With this implementation, TSC will throw an error if there are any missing properties (or typos) in the partial configuration.
Additional Notes
AutoInstrumentationConfigurationtype from core package; it is part ofDatadogProviderprops, so it should have been exposed to users anyway:Changed dev-dependency of core package to
"@datadog/mobile-react-native": "workspace:packages/core"to be able to test changes in core while making changes to the codepush package; we can revert this if it causes problems when preparing the releaseRefactored codepush unit tests to use
requireinstead ofimport, to be able to calljest.resetModules()before each test. The issue is that we have to test a logic that is not invoked when DatadogProvider has been already initialized, and itsisInitializedstatic property is set totrue. For the core package we have an internal method that allows us to reset this value for testing purposes, but it is not accessible from the codepush package.Added two unit tests to verify the behaviour when passing a configuration of type
FileBasedConfigurationMinor changes to the core package to allow reliable mocking of functions for codepush unit tests
Review checklist (to be filled by reviewers)