feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTComponentViewRegistry.h>
#import <React/RCTViewComponentView.h>
#import <XCTest/XCTest.h>
@interface RCTComponentViewRegistryTests : XCTestCase
@end
using namespace facebook::react;
@implementation RCTComponentViewRegistryTests {
RCTComponentViewRegistry *_componentViewRegistry;
}
- (void)setUp
{
[super setUp];
_componentViewRegistry = [RCTComponentViewRegistry new];
[_componentViewRegistry.componentViewFactory registerComponentViewClass:[RCTViewComponentView class]];
}
- (void)testComponentViewDescriptorWithTag
{
XCTAssertThrows(
^{
Tag nonExistingTag = 12;
[self->_componentViewRegistry componentViewDescriptorWithTag:nonExistingTag];
}(),
@"Should throw: `Attempt to query unregistered component`");
Tag existingTag = 2;
auto newViewDescriptor = [_componentViewRegistry
dequeueComponentViewWithComponentHandle:[RCTViewComponentView componentDescriptorProvider].handle
tag:existingTag];
XCTAssertNoThrow(^{
auto componentDescriptor = [self->_componentViewRegistry componentViewDescriptorWithTag:existingTag];
XCTAssertEqual(newViewDescriptor, componentDescriptor);
}());
}
- (void)testFindComponentViewWithTag
{
Tag nonExistingTag = 12;
XCTAssertNil([_componentViewRegistry findComponentViewWithTag:nonExistingTag]);
Tag existingTag = 2;
auto newViewDescriptor = [_componentViewRegistry
dequeueComponentViewWithComponentHandle:[RCTViewComponentView componentDescriptorProvider].handle
tag:existingTag];
XCTAssertEqual(newViewDescriptor.view, [_componentViewRegistry findComponentViewWithTag:existingTag]);
}
- (void)testDequeueAndEnqueue
{
Tag existingTag = 2;
auto newViewDescriptor = [_componentViewRegistry
dequeueComponentViewWithComponentHandle:[RCTViewComponentView componentDescriptorProvider].handle
tag:existingTag];
XCTAssertThrows(
^{
[self->_componentViewRegistry
dequeueComponentViewWithComponentHandle:[RCTViewComponentView componentDescriptorProvider].handle
tag:existingTag];
}(),
@"Should throw: `Attempt to dequeue already registered component`");
XCTAssertThrows(
^{
Tag nonExistingTag = 12;
[self->_componentViewRegistry
enqueueComponentViewWithComponentHandle:[RCTViewComponentView componentDescriptorProvider].handle
tag:nonExistingTag
componentViewDescriptor:newViewDescriptor];
}(),
@"Should throw: `Attempt to enqueue unregistered component`");
}
@end

View File

@@ -0,0 +1,471 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTParagraphComponentAccessibilityProvider.h>
#import <React/RCTParagraphComponentView.h>
#import <XCTest/XCTest.h>
#import <react/renderer/attributedstring/AttributedString.h>
#import <react/renderer/attributedstring/ParagraphAttributes.h>
#import <react/renderer/attributedstring/TextAttributes.h>
#import <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#import <react/renderer/components/root/RootComponentDescriptor.h>
#import <react/renderer/components/text/ParagraphComponentDescriptor.h>
#import <react/renderer/components/text/ParagraphShadowNode.h>
#import <react/renderer/components/text/ParagraphState.h>
#import <react/renderer/components/text/RawTextComponentDescriptor.h>
#import <react/renderer/components/text/RawTextShadowNode.h>
#import <react/renderer/components/text/TextComponentDescriptor.h>
#import <react/renderer/components/text/TextShadowNode.h>
#import <react/renderer/components/view/ViewComponentDescriptor.h>
#import <react/renderer/element/ComponentBuilder.h>
#import <react/renderer/element/Element.h>
#import <react/renderer/element/testUtils.h>
#import <react/renderer/textlayoutmanager/RCTTextLayoutManager.h>
#import <react/renderer/textlayoutmanager/TextLayoutManager.h>
@interface RCTParagraphComponentAccessibilityProviderTests : XCTestCase
@end
using namespace facebook;
using namespace facebook::react;
//┌── RootShadowNode ─────────────────────────────┐
//│ │
//│┌─── ParagraphShadowNodeA ─────────────────────────┐ │
//││ ┌─AA(AAA) ─────────┐ ┌─AB(ABA) ─┐ ┌─AC(ACA)────┐ │ │
//││ │ Please check out │ │ Facebook │ │ and │ │ │
//││ └──────────────────┘ └──────────┘ └────────────┘ │ │
//││ ┌─AD(ADA) ──┐ ┌──AE(AEA) ──────────────────────┐ │ │
//││ │ Instagram │ │ for a full description. │ │ │
//││ └───────────┘ └────────────────────────────────┘ │ │
//│└──────────────────────────────────────────────────┘ │
//│ │
//│ │
//│┌── ParagraphShadowNodeB ──────────────────────────┐ │
//││ ┌───BA(BAA) ───────────────────────────────────┐ │ │
//││ │ Lorem ipsum dolor sit amet, consectetur │ │ │
//││ │ adipiscing elit. Maecenas ut risus et sapien │ │ │
//││ │ bibendum volutpat. Nulla facilisi. Cras │ │ │
//││ │ imperdiet gravida tincidunt. │ │ │
//││ └──────────────────────────────────────────────┘ │ │
//││ ┌─BB(BBA) ─────────────────────────────────────┐ │ │
//││ │ In tempor, tellus et vestibulum venenatis, │ │ │
//││ │ lorem nunc eleifend lectus, a consectetur │ │ │
//││ │ magna augue at arcu. │ │ │
//││ └──────────────────────────────────────────────┘ │ │
//│└──────────────────────────────────────────────────┘ │
//│ │
//│┌── ParagraphShadowNodeC ──────────────────────────┐ │
//││ ┌─CA(CAA) ────────┐ │ │
//││ │ Lorem ipsum │ │ │
//││ └─────────────────┘ │ │
//││ ┌─CB(CBA) ─────────────────────────────────────┐ │ │
//││ │ dolor sit amet, consectetur adipiscing elit. │ │ │
//││ │Maecenas ut risus et sapien bibendum volutpat.│ │ │
//││ │ Nulla facilisi. Cras imperdiet gravida │ │ │
//││ │ tincidunt. In tempor, tellus et vestibulum │ │ │
//││ │ venenatis, lorem nunc eleifend lectus, a │ │ │
//││ │ consectetur magna augue at arcu. │ │ │
//││ └──────────────────────────────────────────────┘ │ │
//││ ┌─CC(CCA) ────────┐ │ │
//││ │ See Less │ │ │
//││ └─────────────────┘ │ │
//│└──────────────────────────────────────────────────┘ │
//│ │
//└─────────────────────────────────────────────────────┘
@implementation RCTParagraphComponentAccessibilityProviderTests {
std::shared_ptr<ComponentBuilder> builder_;
std::shared_ptr<RootShadowNode> rootShadowNode_;
std::shared_ptr<ParagraphShadowNode> ParagrahShadowNodeA_;
std::shared_ptr<ParagraphShadowNode> ParagrahShadowNodeB_;
std::shared_ptr<ParagraphShadowNode> ParagrahShadowNodeC_;
std::shared_ptr<TextShadowNode> TextShadowNodeAA_;
std::shared_ptr<TextShadowNode> TextShadowNodeAB_;
std::shared_ptr<TextShadowNode> TextShadowNodeAC_;
std::shared_ptr<TextShadowNode> TextShadowNodeAD_;
std::shared_ptr<TextShadowNode> TextShadowNodeAE_;
std::shared_ptr<TextShadowNode> TextShadowNodeBA_;
std::shared_ptr<TextShadowNode> TextShadowNodeBB_;
std::shared_ptr<TextShadowNode> TextShadowNodeCA_;
std::shared_ptr<TextShadowNode> TextShadowNodeCB_;
std::shared_ptr<TextShadowNode> TextShadowNodeCC_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeAAA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeABA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeACA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeADA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeAEA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeBAA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeBBA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeCAA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeCBA_;
std::shared_ptr<RawTextShadowNode> RawTextShadowNodeCCA_;
}
- (void)setUp
{
[super setUp];
builder_ = std::make_shared<ComponentBuilder>((simpleComponentBuilder()));
auto element =
Element<RootShadowNode>()
.reference(rootShadowNode_)
.tag(1)
.props([] {
auto sharedProps = std::make_shared<RootProps>();
auto &props = *sharedProps;
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
auto &yogaStyle = props.yogaStyle;
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200));
return sharedProps;
})
.children({
Element<ParagraphShadowNode>()
.reference(ParagrahShadowNodeA_)
.props([] {
auto sharedProps = std::make_shared<ParagraphProps>();
auto &props = *sharedProps;
props.accessible = true;
auto &yogaStyle = props.yogaStyle;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(0));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200));
return sharedProps;
})
.children({
Element<TextShadowNode>()
.reference(TextShadowNodeAA_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeAAA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "Please check out ";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeAB_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Link;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeABA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "facebook";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeAC_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeACA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = " and ";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeAD_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Link;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeADA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "instagram";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeAE_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeAEA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = " for a full description.";
return sharedProps;
})}),
}),
Element<ParagraphShadowNode>()
.reference(ParagrahShadowNodeB_)
.props([] {
auto sharedProps = std::make_shared<ParagraphProps>();
auto &props = *sharedProps;
props.accessible = true;
auto &yogaStyle = props.yogaStyle;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(30));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(50));
return sharedProps;
})
.children({
Element<TextShadowNode>()
.reference(TextShadowNodeBA_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Link;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeBAA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ut risus et sapien bibendum volutpat. Nulla facilisi. Cras imperdiet gravida tincidunt. ";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeBB_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeBBA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text =
"In tempor, tellus et vestibulum venenatis, lorem nunc eleifend lectus, a consectetur magna augue at arcu.";
return sharedProps;
})}),
}),
Element<ParagraphShadowNode>()
.reference(ParagrahShadowNodeC_)
.props([] {
auto sharedProps = std::make_shared<ParagraphProps>();
auto &props = *sharedProps;
props.accessible = true;
auto &yogaStyle = props.yogaStyle;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(90));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(50));
return sharedProps;
})
.children({
Element<TextShadowNode>()
.reference(TextShadowNodeCA_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Link;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeCAA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "Lorem ipsum";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeCB_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeCBA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text =
" dolor sit amet, consectetur adipiscing elit. Maecenas ut risus et sapien bibendum volutpat. Nulla facilisi. Cras imperdiet gravida tincidunt. In tempor, tellus et vestibulum venenatis, lorem nunc eleifend lectus, a consectetur magna augue at arcu. ";
return sharedProps;
})}),
Element<TextShadowNode>()
.reference(TextShadowNodeCC_)
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Button;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeCCA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "See Less";
return sharedProps;
})}),
}),
});
builder_->build(element);
rootShadowNode_->layoutIfNeeded();
}
static ParagraphShadowNode::ConcreteState::Shared stateWithShadowNode(
std::shared_ptr<ParagraphShadowNode> paragraphShadowNode)
{
auto sharedState =
std::static_pointer_cast<ParagraphShadowNode::ConcreteState const>(paragraphShadowNode->getState());
return sharedState;
}
- (void)testAttributedString
{
ParagraphShadowNode::ConcreteState::Shared _stateA = stateWithShadowNode(ParagrahShadowNodeA_);
RCTParagraphComponentView *paragraphComponentViewA = [RCTParagraphComponentView new];
[paragraphComponentViewA updateProps:ParagrahShadowNodeA_->getProps() oldProps:nullptr];
[paragraphComponentViewA updateState:_stateA oldState:nil];
ParagraphShadowNode::ConcreteState::Shared _stateB = stateWithShadowNode(ParagrahShadowNodeB_);
RCTParagraphComponentView *paragraphComponentViewB = [RCTParagraphComponentView new];
[paragraphComponentViewB updateProps:ParagrahShadowNodeB_->getProps() oldProps:nullptr];
[paragraphComponentViewB updateState:_stateB oldState:nil];
ParagraphShadowNode::ConcreteState::Shared _stateC = stateWithShadowNode(ParagrahShadowNodeC_);
RCTParagraphComponentView *paragraphComponentViewC = [RCTParagraphComponentView new];
[paragraphComponentViewC updateProps:ParagrahShadowNodeC_->getProps() oldProps:nullptr];
[paragraphComponentViewC updateState:_stateC oldState:nil];
// Check the correctness of attributedString
XCTAssert([[paragraphComponentViewA.attributedText string]
isEqual:@"Please check out facebook and instagram for a full description."]);
XCTAssertEqual(_stateA->getData().attributedString.getFragments().size(), 5);
XCTAssert([[paragraphComponentViewB.attributedText string]
isEqual:
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ut risus et sapien bibendum volutpat. Nulla facilisi. Cras imperdiet gravida tincidunt. In tempor, tellus et vestibulum venenatis, lorem nunc eleifend lectus, a consectetur magna augue at arcu."]);
XCTAssertEqual(_stateB->getData().attributedString.getFragments().size(), 2);
XCTAssert([[paragraphComponentViewC.attributedText string]
isEqual:
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ut risus et sapien bibendum volutpat. Nulla facilisi. Cras imperdiet gravida tincidunt. In tempor, tellus et vestibulum venenatis, lorem nunc eleifend lectus, a consectetur magna augue at arcu. See Less"]);
XCTAssertEqual(_stateC->getData().attributedString.getFragments().size(), 3);
}
#pragma mark - Accessibility
- (void)testAccessibilityMultipleLinks
{
// initialize the paragraphComponentView to get the accessibilityElements
ParagraphShadowNode::ConcreteState::Shared _state = stateWithShadowNode(ParagrahShadowNodeA_);
RCTParagraphComponentView *paragraphComponentView = [RCTParagraphComponentView new];
[paragraphComponentView updateProps:ParagrahShadowNodeA_->getProps() oldProps:nullptr];
[paragraphComponentView updateState:_state oldState:nil];
NSArray<UIAccessibilityElement *> *elements = [paragraphComponentView accessibilityElements];
// check the number of accessibilityElements
XCTAssert(
elements.count == 3, @"Expected 4 accessibilityElements - one for the whole string, and the rest for the links");
// check accessibility trait
XCTAssert(
elements[1].accessibilityTraits & UIAccessibilityTraitLink,
@"Expected the second accessibilityElement has link trait");
XCTAssert(
elements[2].accessibilityTraits & UIAccessibilityTraitLink,
@"Expected the second accessibilityElement has link trait");
}
- (void)testAccessibilityLinkWrappingMultipleLines
{
ParagraphShadowNode::ConcreteState::Shared _state = stateWithShadowNode(ParagrahShadowNodeB_);
RCTParagraphComponentView *paragraphComponentView = [RCTParagraphComponentView new];
[paragraphComponentView updateProps:ParagrahShadowNodeB_->getProps() oldProps:nullptr];
[paragraphComponentView updateState:_state oldState:nil];
NSArray<UIAccessibilityElement *> *elements = [paragraphComponentView accessibilityElements];
XCTAssert(elements.count == 2, @"Expected 2 accessibilityElements - one for the whole string, and one for the link");
XCTAssert(
elements[1].accessibilityTraits & UIAccessibilityTraitLink,
@"Expected the second accessibilityElement has link trait");
}
- (void)testAccessibilityTruncatedText
{
ParagraphShadowNode::ConcreteState::Shared _state = stateWithShadowNode(ParagrahShadowNodeC_);
RCTParagraphComponentView *paragraphComponentView = [RCTParagraphComponentView new];
[paragraphComponentView updateProps:ParagrahShadowNodeC_->getProps() oldProps:nullptr];
[paragraphComponentView updateState:_state oldState:nil];
NSArray<UIAccessibilityElement *> *elements = [paragraphComponentView accessibilityElements];
XCTAssert(elements.count == 2, @"Expected 2 accessibilityElements - one for the whole string, and one for the link");
XCTAssert(
elements[1].accessibilityTraits & UIAccessibilityTraitLink,
@"Expected the second accessibilityElement has link trait");
}
- (void)testEntireParagraphLink
{
std::shared_ptr<RootShadowNode> rootShadowNode;
std::shared_ptr<ParagraphShadowNode> paragrahShadowNode;
auto element = Element<RootShadowNode>()
.reference(rootShadowNode)
.tag(1)
.props([] {
auto sharedProps = std::make_shared<RootProps>();
auto &props = *sharedProps;
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
auto &yogaStyle = props.yogaStyle;
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(200));
return sharedProps;
})
.children({
Element<ParagraphShadowNode>()
.reference(paragrahShadowNode)
.props([] {
auto sharedProps = std::make_shared<ParagraphProps>();
auto &props = *sharedProps;
props.accessible = true;
props.accessibilityTraits = AccessibilityTraits::Link;
auto &yogaStyle = props.yogaStyle;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::value::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::value::points(90));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::value::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::value::points(20));
return sharedProps;
})
.children({
Element<TextShadowNode>()
.props([] {
auto sharedProps = std::make_shared<TextProps>();
auto &props = *sharedProps;
props.textAttributes.accessibilityRole = AccessibilityRole::Link;
return sharedProps;
})
.children({Element<RawTextShadowNode>().reference(RawTextShadowNodeABA_).props([] {
auto sharedProps = std::make_shared<RawTextProps>();
auto &props = *sharedProps;
props.text = "A long text that happens to be a link";
return sharedProps;
})}),
}),
});
builder_->build(element);
rootShadowNode->layoutIfNeeded();
ParagraphShadowNode::ConcreteState::Shared _state = stateWithShadowNode(paragrahShadowNode);
RCTParagraphComponentView *paragraphComponentView = [RCTParagraphComponentView new];
[paragraphComponentView updateProps:paragrahShadowNode->getProps() oldProps:nullptr];
[paragraphComponentView updateState:_state oldState:nil];
NSArray<UIAccessibilityElement *> *elements = paragraphComponentView.accessibilityElements;
XCTAssertEqual(elements.count, 1);
XCTAssertTrue(elements[0].accessibilityTraits & UIAccessibilityTraitLink);
}
@end