|
| 1 | +import React, {useState} from 'react'; |
| 2 | +import {Button, TextInput, View, Text} from 'react-native'; |
| 3 | +import {render, fireEvent, waitFor, act} from '@testing-library/react-native'; |
| 4 | +import Realm from 'realm'; |
| 5 | +import {createRealmContext} from '@realm/react'; |
| 6 | +import Address from '../../Models/Address'; |
| 7 | +import Contact from '../../Models/Contact'; |
| 8 | + |
| 9 | +const realmConfig = { |
| 10 | + schema: [Address, Contact], |
| 11 | + deleteRealmIfMigrationNeeded: true, |
| 12 | +}; |
| 13 | + |
| 14 | +const {RealmProvider, useQuery, useRealm} = createRealmContext(realmConfig); |
| 15 | + |
| 16 | +let assertionRealm; |
| 17 | + |
| 18 | +// test describe block for the embedded objects page |
| 19 | +describe('embedded objects tests', () => { |
| 20 | + beforeEach(async () => { |
| 21 | + // we will use this Realm for assertions to access Realm Objects outside of a Functional Component (like required by @realm/react) |
| 22 | + assertionRealm = await Realm.open(realmConfig); |
| 23 | + |
| 24 | + // // delete every object in the realmConfig in the Realm to make test idempotent |
| 25 | + assertionRealm.write(() => { |
| 26 | + assertionRealm.delete(assertionRealm.objects(Contact)); |
| 27 | + |
| 28 | + new Contact(assertionRealm, { |
| 29 | + name: 'John Smith', |
| 30 | + _id: new Realm.BSON.ObjectID(), |
| 31 | + address: { |
| 32 | + street: '1 Home Street', |
| 33 | + city: 'New York City', |
| 34 | + country: 'USA', |
| 35 | + postalCode: '12345', |
| 36 | + }, |
| 37 | + }); |
| 38 | + |
| 39 | + new Contact(assertionRealm, { |
| 40 | + name: 'Jane Doe', |
| 41 | + _id: new Realm.BSON.ObjectID(), |
| 42 | + address: { |
| 43 | + street: '2 Home Street', |
| 44 | + city: 'Kansas City', |
| 45 | + country: 'USA', |
| 46 | + postalCode: '54321', |
| 47 | + }, |
| 48 | + }); |
| 49 | + }); |
| 50 | + }); |
| 51 | + afterAll(() => { |
| 52 | + // close realm |
| 53 | + if (!assertionRealm.isClosed) { |
| 54 | + assertionRealm.close(); |
| 55 | + } |
| 56 | + }); |
| 57 | + it("should create and read an embedded object", async () => { |
| 58 | + // :snippet-start: create-embedded-object |
| 59 | + // :replace-start: { |
| 60 | + // "terms": { |
| 61 | + // "LeBron James": "", |
| 62 | + // "1 Goat Drive": "", |
| 63 | + // "Cleveland": "", |
| 64 | + // "USA": "", |
| 65 | + // "12345": "", |
| 66 | + // " testID='submitContactBtn'": "" |
| 67 | + // } |
| 68 | + // } |
| 69 | + |
| 70 | + const CreateContact = () => { |
| 71 | + const [name, setContactName] = useState('LeBron James'); |
| 72 | + const [street, setStreet] = useState('1 Goat Drive'); |
| 73 | + const [city, setCity] = useState('Cleveland'); |
| 74 | + const [country, setCountry] = useState('USA'); |
| 75 | + const [postalCode, setPostalCode] = useState('12345'); |
| 76 | + const realm = useRealm(); |
| 77 | + |
| 78 | + const submitContact = () => { |
| 79 | + // Create a Contact within a write transaction |
| 80 | + realm.write(() => { |
| 81 | + // Create an embedded Address object |
| 82 | + const address = { |
| 83 | + street, |
| 84 | + city, |
| 85 | + country, |
| 86 | + postalCode, |
| 87 | + }; |
| 88 | + new Contact(realm, { |
| 89 | + _id: new Realm.BSON.ObjectID(), |
| 90 | + name, |
| 91 | + address, // Embed the address in the Contact object |
| 92 | + }); |
| 93 | + }); |
| 94 | + }; |
| 95 | + return ( |
| 96 | + <View> |
| 97 | + <TextInput value={name} onChangeText={text => setContactName(text)} /> |
| 98 | + <TextInput value={street} onChangeText={text => setStreet(text)} /> |
| 99 | + <TextInput value={city} onChangeText={text => setCity(text)} /> |
| 100 | + <TextInput value={country} onChangeText={text => setCountry(text)} /> |
| 101 | + <TextInput value={postalCode} onChangeText={text => setPostalCode(text)} /> |
| 102 | + <Button title='Submit Contact' testID='submitContactBtn' onPress={submitContact} /> |
| 103 | + </View> |
| 104 | + ); |
| 105 | + }; |
| 106 | + // :replace-end: |
| 107 | + // :snippet-end: |
| 108 | + const App = () => ( |
| 109 | + <RealmProvider> |
| 110 | + <CreateContact/> |
| 111 | + </RealmProvider> |
| 112 | + ); |
| 113 | + const {findByTestId} = render(<App />); |
| 114 | + const submitContactBtn = await waitFor(() => findByTestId('submitContactBtn'), { |
| 115 | + timeout: 5000, |
| 116 | + }); |
| 117 | + await act(async () => { |
| 118 | + fireEvent.press(submitContactBtn); |
| 119 | + }); |
| 120 | + // check if the new Contact object has been created |
| 121 | + const contact = assertionRealm.objects(Contact).filtered("name == 'LeBron James'")[0]; |
| 122 | + expect(contact.name).toBe('LeBron James'); |
| 123 | + expect(contact.address.street).toBe('1 Goat Drive'); |
| 124 | + expect(contact.address.city).toBe('Cleveland'); |
| 125 | + expect(contact.address.country).toBe('USA'); |
| 126 | + expect(contact.address.postalCode).toBe('12345'); |
| 127 | + }); |
| 128 | + it('should query for an embedded object', async () => { |
| 129 | + // :snippet-start: query-embedded-object |
| 130 | + // :replace-start: { |
| 131 | + // "terms": { |
| 132 | + // " testID = 'addressText'": "" |
| 133 | + // } |
| 134 | + // } |
| 135 | + const ContactList = () => { |
| 136 | + // Query for all Contact objects |
| 137 | + const contacts = useQuery(Contact); |
| 138 | + |
| 139 | + // Run the `.filtered()` method on all the returned Contacts to find the |
| 140 | + // contact with the name "John Smith" and the corresponding street address |
| 141 | + const contactAddress = contacts |
| 142 | + .filtered("name == 'John Smith'")[0].address.street; |
| 143 | + |
| 144 | + return( |
| 145 | + <View> |
| 146 | + <Text>John Smith's street address:</Text> |
| 147 | + <Text testID = 'addressText'>{contactAddress}</Text> |
| 148 | + </View> |
| 149 | + ); |
| 150 | + }; |
| 151 | + // :replace-end: |
| 152 | + // :snippet-end: |
| 153 | + const App = () => ( |
| 154 | + <RealmProvider> |
| 155 | + <ContactList /> |
| 156 | + </RealmProvider> |
| 157 | + ); |
| 158 | + const {getByTestId} = render(<App />); |
| 159 | + |
| 160 | + // test that querying for name works |
| 161 | + const contactAddress = await waitFor(() => getByTestId('addressText'), { |
| 162 | + timeout: 5000, |
| 163 | + }); |
| 164 | + expect(contactAddress.props.children).toBe('1 Home Street'); |
| 165 | + }); |
| 166 | + it('should delete an embedded object', async () => { |
| 167 | + // :snippet-start: delete-embedded-object |
| 168 | + // :replace-start: { |
| 169 | + // "terms": { |
| 170 | + // " testID = 'contactNameText'": "", |
| 171 | + // " testID = 'deleteContactBtn'": "" |
| 172 | + // } |
| 173 | + // } |
| 174 | + const ContactInfo = ({contactName}) => { |
| 175 | + const contacts = useQuery(Contact); |
| 176 | + const toDelete = contacts.filtered(`name == '${contactName}'`)[0] |
| 177 | + const realm = useRealm(); |
| 178 | + |
| 179 | + const deleteContact = () => { |
| 180 | + realm.write(() => { |
| 181 | + // Deleting the contact also deletes the embedded address of that contact |
| 182 | + realm.delete( |
| 183 | + toDelete |
| 184 | + ); |
| 185 | + }); |
| 186 | + }; |
| 187 | + return ( |
| 188 | + <View> |
| 189 | + <Text testID='contactNameText'>{contactName}</Text> |
| 190 | + <Button testID='deleteContactBtn' onPress={deleteContact} title='Delete Contact' /> |
| 191 | + </View> |
| 192 | + ); |
| 193 | + }; |
| 194 | + // :replace-end: |
| 195 | + // :snippet-end: |
| 196 | + const App = () => ( |
| 197 | + <RealmProvider> |
| 198 | + <ContactInfo contactName='John Smith'/> |
| 199 | + </RealmProvider> |
| 200 | + ); |
| 201 | + const {findByTestId} = render(<App />); |
| 202 | + const contactNameText = await waitFor(() => findByTestId('contactNameText'), { |
| 203 | + timeout: 5000, |
| 204 | + }); |
| 205 | + expect(contactNameText.props.children).toBe('John Smith'); |
| 206 | + |
| 207 | + const deleteContactBtn = await waitFor(() => findByTestId('deleteContactBtn'), { |
| 208 | + timeout: 5000, |
| 209 | + }); |
| 210 | + await act(async () => { |
| 211 | + fireEvent.press(deleteContactBtn); |
| 212 | + }); |
| 213 | + // check if the new Contact object has been deleted |
| 214 | + const contact = assertionRealm.objects(Contact) |
| 215 | + expect(contact.length).toBe(1); |
| 216 | + }); |
| 217 | + it("should update an embedded object", async () => { |
| 218 | + // :snippet-start: update-embedded-object |
| 219 | + // :replace-start: { |
| 220 | + // "terms": { |
| 221 | + // " testID='updateContactBtn'": "", |
| 222 | + // "3 jefferson lane": "" |
| 223 | + // } |
| 224 | + // } |
| 225 | + // Find the contact you want to update |
| 226 | + const UpdateContact = ({contactName}) => { |
| 227 | + const [street, setStreet] = useState('3 jefferson lane'); |
| 228 | + const contact = useQuery(Contact).filtered(`name == '${contactName}'`)[0]; |
| 229 | + const realm = useRealm(); |
| 230 | + |
| 231 | + const updateStreet = () => { |
| 232 | + // Modify the property of the embedded Address object in a write transaction |
| 233 | + realm.write(() => { |
| 234 | + // Update the address directly through the contact |
| 235 | + contact.address.street = street; |
| 236 | + }); |
| 237 | + }; |
| 238 | + return ( |
| 239 | + <View> |
| 240 | + <Text>{contact.name}</Text> |
| 241 | + <TextInput value={street} onChangeText={setStreet} placeholder='Enter New Street Address' /> |
| 242 | + <Button testID='updateContactBtn' onPress={updateStreet} title='Update Street Address' /> |
| 243 | + </View> |
| 244 | + ); |
| 245 | + }; |
| 246 | + // :replace-end: |
| 247 | + // :snippet-end: |
| 248 | + const App = () => ( |
| 249 | + <RealmProvider> |
| 250 | + <UpdateContact contactName='John Smith'/> |
| 251 | + </RealmProvider> |
| 252 | + ); |
| 253 | + const {findByTestId} = render(<App />); |
| 254 | + const updateContactBtn = await waitFor(() => findByTestId('updateContactBtn'), { |
| 255 | + timeout: 5000, |
| 256 | + }); |
| 257 | + await act(async () => { |
| 258 | + fireEvent.press(updateContactBtn); |
| 259 | + }); |
| 260 | + // check if the new Contact object has been updated |
| 261 | + const contact = assertionRealm.objects(Contact).filtered("name == 'John Smith'")[0]; |
| 262 | + expect(contact.address.street).toBe('3 jefferson lane'); |
| 263 | + }); |
| 264 | + it("should overwrite an embedded object", async () => { |
| 265 | + // :snippet-start: overwrite-embedded-object |
| 266 | + // :replace-start: { |
| 267 | + // "terms": { |
| 268 | + // " testID='overwriteContactBtn'": "", |
| 269 | + // "12 Grimmauld Place": "", |
| 270 | + // "London": "", |
| 271 | + // "UK": "", |
| 272 | + // "E1 7AA": "" |
| 273 | + // } |
| 274 | + // } |
| 275 | + const OverwriteContact = ({contactName}) => { |
| 276 | + const [street, setStreet] = useState('12 Grimmauld Place'); |
| 277 | + const [city, setCity] = useState('London'); |
| 278 | + const [country, setCountry] = useState('UK'); |
| 279 | + const [postalCode, setPostalCode] = useState('E1 7AA'); |
| 280 | + const contact = useQuery(Contact).filtered(`name == '${contactName}'`)[0]; |
| 281 | + const realm = useRealm(); |
| 282 | + |
| 283 | + const updateAddress = () => { |
| 284 | + realm.write(() => { |
| 285 | + // Within a write transaction, overwrite the embedded object with the new address |
| 286 | + const address = { |
| 287 | + street, |
| 288 | + city, |
| 289 | + country, |
| 290 | + postalCode, |
| 291 | + }; |
| 292 | + contact.address = address; |
| 293 | + }); |
| 294 | + }; |
| 295 | + return ( |
| 296 | + <View> |
| 297 | + <Text>{contact.name}</Text> |
| 298 | + <Text>Enter the new address:</Text> |
| 299 | + <TextInput value={street} onChangeText={setStreet} placeholder='Street' /> |
| 300 | + <TextInput value={city} onChangeText={setCity} placeholder='City' /> |
| 301 | + <TextInput value={country} onChangeText={setCountry} placeholder='Country' /> |
| 302 | + <TextInput value={postalCode} onChangeText={setPostalCode} placeholder='Postal Code' /> |
| 303 | + <Button testID='overwriteContactBtn' onPress={updateAddress} title='Overwrite Address' /> |
| 304 | + </View> |
| 305 | + ); |
| 306 | + }; |
| 307 | + // :replace-end: |
| 308 | + // :snippet-end: |
| 309 | + const App = () => ( |
| 310 | + <RealmProvider> |
| 311 | + <OverwriteContact contactName='John Smith'/> |
| 312 | + </RealmProvider> |
| 313 | + ); |
| 314 | + const {findByTestId} = render(<App />); |
| 315 | + const overwriteContactBtn = await waitFor(() => findByTestId('overwriteContactBtn'), { |
| 316 | + timeout: 5000, |
| 317 | + }); |
| 318 | + await act(async () => { |
| 319 | + fireEvent.press(overwriteContactBtn); |
| 320 | + }); |
| 321 | + // check if the new Contact object has been overwritten |
| 322 | + const contact = assertionRealm.objects(Contact).filtered("name == 'John Smith'")[0]; |
| 323 | + expect(contact.address.street).toBe('12 Grimmauld Place'); |
| 324 | + expect(contact.address.city).toBe('London'); |
| 325 | + expect(contact.address.country).toBe('UK'); |
| 326 | + expect(contact.address.postalCode).toBe('E1 7AA'); |
| 327 | + }); |
| 328 | +}); |
0 commit comments