Slide 1

Slide 1 text

4IBSF&YUFOTJPOͷ6*5FTU for )","5"5FTU/JHIU

Slide 2

Slide 2 text

} var employedBy = "YUMEMI Inc." var job = "iOS Tech Lead" var favoriteLanguage = "Swift" var twitter = "@lovee" var qiita = "lovee" var github = "el-hoshino" var additionalInfo = """ ཏখࠇઓهʢϩγϟΦϔΠηϯΩʣөը؍Α͏ʂ """ final class Me: Developable, Talkable {

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

4IBSF&YUFOTJPOΛରԠͨ͠ɻ 6*5FTUΛ͍ͨ͠ɻ Ͳ͏͢Ε͹͍͍ʁ

Slide 8

Slide 8 text

func testQRCodeGenerationFromSafari() { let app = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari") app.launch() XCTContext.runActivity(named: "Go to about:blank page") { _ -> Void in let urlBar = app.otherElements["topBrowserBar"] urlBar.tap() urlBar.typeText("about:blank") app.buttons["Go"].tap() } XCTContext.runActivity(named: "Call Share menu") { _ -> Void in let shareButton = app.buttons["Share"] shareButton.tap() } XCTContext.runActivity(named: "Open QuickshaRe") { _ -> Void in let shareList = app.otherElements["ActivityListView"] XCTAssert(shareList.waitForExistence(timeout: 2)) let cell = shareList.cells.matching(identifier: "Activity").allElementsBoundByIndex[1] cell.tap() } XCTContext.runActivity(named: "Check label and image display") { _ -> Void in let view = app.otherElements["Share View"] let label = view.staticTexts["about:blank"] let image = view.images["QR Image"] XCTAssert(view.waitForExistence(timeout: 2)) XCTAssert(label.exists) XCTAssert(image.exists) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil)! let qrCIImage = CIImage(image: image.screenshot().image)! let features = detector.features(in: qrCIImage) as! [CIQRCodeFeature] XCTAssertEqual(features[0].messageString, "about:blank") } }

Slide 9

Slide 9 text

6*5FTUͱ6OJU5FTUͷҧ͍ w 6OJU5FTUɿϝιου౳ͷॲཧʹର͢ΔϩδοΫͷςετ w ΞϓϦຊମΛ@testable import͠ɺϝιου΍ΦϒδΣΫτ ౳ͷςετର৅Λ࣮ࡍʹݺͼग़ͯ͠ಈ࡞Λ֬ೝ w ඞཁʹԠͯ͡ςετର৅ʹςετ޲͚ͷґଘΛ஫ೖՄೳ w ΞϓϦͷ࣮૷Λʢ͋Δఔ౓ʣ೺Ѳͨ͠ϗϫΠτϘοΫεςετ w 6*5FTUɿϏϧυࡁΈͷΞϓϦΛ௚઀ಈ͔͢ςετ w ΞϓϦຊମΛ@testable importͤͣʹ௚઀ΞϓϦΛૢ࡞ͯ͠ ಈ࡞Λ֬ೝ w ςετ޲͚ͷґଘ஫ೖ͸೉͍͠ w ΞϓϦͷ࣮૷Λશ͘೺Ѳ͠ͳ͍ϒϥοΫϘοΫεςετ

Slide 10

Slide 10 text

ς ε τ ର ৅ ͷ ຊ ମ Ξ ϓ Ϧ ࣮ ࡍ ͷ ς ε τ λ ʔ ή ỽ τ ͔ Β Ϗ ϧ υ ͠ ͨ Ξ ϓ Ϧ

Slide 11

Slide 11 text

2VJDLTIB3F ։͚ ͸͍

Slide 12

Slide 12 text

4BGBSJ։͚ ͸͍

Slide 13

Slide 13 text

let app = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari") app.launch()

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

ΞϓϦ͸։͚ͨɻ Ͳ͏ૢ࡞͢Ε͹͍͍ͷʁ

Slide 16

Slide 16 text

.staticTexts["Some Text"] .textFields["Placeholder Text"] .buttons["Button Title"] .images["Accessibility Identifier"] .otherElements["Identifier"] .exists .waitForExistence(timeout: 2) .tap() .typeText("Some Typing") // etc...

Slide 17

Slide 17 text

.staticTexts["Some Text"] .textFields["Placeholder Text"] .buttons["Button Title"] .images["Accessibility Identifier"] .otherElements["Identifier"] .exists .waitForExistence(timeout: 2) .tap() .typeText("Some Typing") // etc... ͜ΕΒͷ"1*Λ૊Έ߹Θͤͯ ΞϓϦʹରͯ͠র߹΍ૢ࡞Λ༩͑Δ

Slide 18

Slide 18 text

ڞ༗ϝχϡʔରԠͷ6*5FTU֬ೝखॱ 4BGBSJΛࢦఆͷ63-ʹભҠ ಡΈࠐΈ͕ऴΘͬͨΒڞ༗ϝχϡʔΛ։͘ ڞ༗ϝχϡʔ͔Β֘౰ΞϓϦΛ։͘ ։͍ͨը໘͕ਖ਼͘͠දࣔͰ͖͍ͯΔ͔ΛνΣοΫ

Slide 19

Slide 19 text

εςοϓɿࢦఆͷ63-ʹભҠ ϒϥ΢βόʔΛԡ͢ ϒϥ΢βόʔʹࢦఆͷ63-Λೖྗ ΩʔϘʔυͷA(PAΩʔΛԡ͢

Slide 20

Slide 20 text

// ϒϥ΢βը໘ͷ্ʹ͋Δϒϥ΢βόʔΛ୳͢ let urlBar = app.otherElements["topBrowserBar"] // ͦͷϒϥ΢βόʔΛԡ͢ urlBar.tap() // ϒϥ΢βόʔʹࢦఆͷจࣈΛೖΕΔ urlBar.typeText("about:blank") // ΩʔϘʔυͷ `Go` ΩʔΛԡ͢ app.buttons["Go"].tap()

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

εςοϓɿڞ༗ϝχϡʔΛ։͘ ڞ༗ϘλϯΛԡ͢

Slide 23

Slide 23 text

// ΞϓϦͷڞ༗ϘλϯΛ୳͢ let shareButton = app.buttons["Share"] // ͦͷڞ༗ϘλϯΛԡ͢ shareButton.tap()

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

εςοϓɿ֘౰ΞϓϦΛ։͘ ڞ༗ϝχϡʔ͕දࣔ͞ΕΔ·Ͱ଴ͭ ڞ༗ϝχϡʔ಺ͷ֘౰ΞϓϦͷΞΠίϯΛԡ͢

Slide 26

Slide 26 text

// ڞ༗ϝχϡʔΛ୳͢ let shareList = app.otherElements["ActivityListView"] // ڞ༗ϝχϡʔ͕දࣔ͞ΕΔ·Ͱ࠷େ 2 ඵ଴ͭ XCTAssert(shareList.waitForExistence(timeout: 2)) // ͦͷڞ༗ϝχϡʔ͔Β֘౰ΞϓϦͷΞΠίϯΛ୳͢ let cell = shareList.cells.matching(identifier: "Activity") .allElementsBoundByIndex[1] // ͦͷΞΠίϯΛԡ͢ cell.tap()

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

εςοϓɿਖ਼͘͠දࣔͰ͖͍ͯΔ͔ ࢦఆͷ63-ςΩετද͕ࣔ͋Δ 23ίʔυը૾ද͕ࣔ͋Δ 23ίʔυΛಡΈऔΕ͹ࢦఆͷ63-ςΩετͰ͋Δ

Slide 29

Slide 29 text

// Share View Λ୳͢ let view = app.otherElements["Share View"] // ࢦఆͷςΩετදࣔΛ୳͢ let label = view.staticTexts["about:blank"] // QR ίʔυը૾දࣔΛ୳͢ let image = view.images["QR Image"] // Share View ͕දࣔ͞ΕΔ·Ͱ࠷େ 2 ඵ଴ͭ XCTAssert(view.waitForExistence(timeout: 2)) // ࢦఆͷ URL ςΩετද͕ࣔ͋Δ͜ͱΛ֬ೝ XCTAssert(label.exists) // QR ίʔυը૾ද͕ࣔ͋Δ͜ͱΛ֬ೝ XCTAssert(image.exists) // ͦͷը૾දࣔΛ QR ίʔυͱͯ͠ಡΈऔΕ͹ࢦఆͷ URL ςΩετͰ͋Δ͜ͱΛ֬ೝ let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil)! let qrCIImage = CIImage(image: image.screenshot().image)! let features = detector.features(in: qrCIImage) as! [CIQRCodeFeature] XCTAssertEqual(features[0].messageString, "about:blank") ౰વͳ͕Β JNQPSU$PSF*NBHF ͕ඞཁ

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

// ڞ༗ϝχϡʔΛ୳͢ let shareList = app.otherElements["ActivityListView"] // ڞ༗ϝχϡʔ͕දࣔ͞ΕΔ·Ͱ࠷େ 2 ඵ଴ͭ XCTAssert(shareList.waitForExistence(timeout: 2)) // ͦͷڞ༗ϝχϡʔ͔Β֘౰ΞϓϦͷΞΠίϯΛ୳͢ let cell = shareList.cells.matching(identifier: "Activity") .allElementsBoundByIndex[1] // ͦͷΞΠίϯΛԡ͢ cell.tap() ͳΜ͡Ό͜Εʂʁ NBUDIJOHʁ "DUJWJUZʁ <>ʁ

Slide 32

Slide 32 text

6*5FTUͰͲ͏΍ͬͯ ը໘ཁૉΛಛఆ͢Δͷ͔

Slide 33

Slide 33 text

// ࢦఆͷςΩετදࣔΛ୳͢ let label = view.staticTexts["about:blank"] ςΩετͳΒ

Slide 34

Slide 34 text

ςΩετͳΒ wͦͷ··["ݻఆςΩετ"]ͰׂΓग़͢ • staticTexts["Text"] • buttons["Button Title"] ˞෺ʹΑͬͯͳ͔ͥऔΕͳ͍ը໘ཁૉ΋͋Δ

Slide 35

Slide 35 text

// QR ίʔυը૾දࣔΛ୳͢ let image = view.images["QR Image"] ςΩετҎ֎Ͱࣗ෼ͷΞϓϦͳΒ

Slide 36

Slide 36 text

ςΩετҎ֎Ͱࣗ෼ͷΞϓϦͳΒ wBccessibilityIdentifierΛઃఆͯ͠ ["Accessibility Identifier"]͔ΒׂΓग़͢ • images["Accessibility Identifier"] • otherElements["Accessibility Identifier"]

Slide 37

Slide 37 text

XCTContext.runActivity(named: "Search Elements") { (activity) -> Void in // app ͔ΒݟΕΔ͢΂ͯͷ otherElements Λ૸ࠪ app.otherElements.allElementsBoundByIndex.forEach { (element) in // ඞͣ element ͕ଘࡏ͠ɺ͔ͭαΠζ͕ zero ͡Όͳ͍͜ͱΛอূ guard element.exists, element.frame.size != .zero else { return } // ֘౰ element ͷεΫϦʔϯγϣοτΛࡱΔ let screenshot = element.screenshot() // εΫϦʔϯγϣοτ͔Βఴ෇Λ࡞Δ let attachment = XCTAttachment(screenshot: screenshot) // ݱࡏͷ activity ʹఴ෇Λ௥Ճ activity.add(attachment) } } ςΩετҎ֎ͰଞਓͷΞϓϦͳΒ

Slide 38

Slide 38 text

ςΩετҎ֎ͰଞਓͷΞϓϦͳΒ ֘౰ͦ͠͏ͳࢠཁૉͷछྨΛશ෦૸ࠪ͢Δ ͦΕΒͷཁૉΛ͢΂ͯεΫγϣΛࡱͬͯϨϙʔτʹఴ෇͢Δ Ϩϙʔτͷఴ෇εΫγϣը૾͔Β֘౰͢ΔཁૉΛ୳͠ग़͠ɺ ఴ෇໊͔Βཁૉ໊Λಛఆ͢Δ

Slide 39

Slide 39 text

XCTContext.runActivity(named: "Search Elements") { activity -> Void in let shareList = app.otherElements["ActivityListView"] XCTAssert(shareList.waitForExistence(timeout: 2)) // ڞ༗ϝχϡʔ ͔ΒݟΕΔ͢΂ͯͷ cell Λ૸ࠪ shareList.cells.allElementsBoundByIndex.forEach { (cell) in guard cell.exists, cell.frame.size != .zero else { return } let screenshot = cell.screenshot() let attachment = XCTAttachment(screenshot: screenshot) activity.add(attachment) } } ଞਓͷΞϓϦͳΒ

Slide 40

Slide 40 text

ݱஈ֊ɺڞ༗ϝχϡʔ͔Β ਖ਼֬ʹࣗ෼ͷΞϓϦϘλϯΛ ׂΓग़͢͜ͱ͸ෆՄೳ ˞ࢀߟɿIUUQTHJTUHJUIVCDPN"WE-FFCEFEGDDBDBEHJTUDPNNFOU

Slide 41

Slide 41 text

// ڞ༗ϝχϡʔΛ୳͢ let shareList = app.otherElements["ActivityListView"] // ڞ༗ϝχϡʔ͕දࣔ͞ΕΔ·Ͱ࠷େ 2 ඵ଴ͭ XCTAssert(shareList.waitForExistence(timeout: 2)) // ͦͷڞ༗ϝχϡʔ͔Β֘౰ΞϓϦͷΞΠίϯΛ୳͢ let cell = shareList.cells.matching(identifier: "Activity") .allElementsBoundByIndex[1] // ͦͷΞΠίϯΛԡ͢ cell.tap() ͳΜ͡Ό͜Εʂʁ NBUDIJOHʁ "DUJWJUZʁ <>ʁ

Slide 42

Slide 42 text

// ͢΂ͯͷηϧ͔Β૸ࠪ let cell = shareList.cells // `Activity` ͷηϧΛநग़ .matching(identifier: "Activity") // ͦͷ 2 ൪໨ͷηϧ .allElementsBoundByIndex[1] ˞࣮ߦ͞ΕΔ୺຤ͷڞ༗ઃఆʹґଘ͢ΔͨΊ$*Ͱอূͤ͞Δ͜ͱ͸ݱࡏෆՄೳ

Slide 43

Slide 43 text

·ͱΊ w 6*5FTU͸ΞϓϦʹରͯ͠௚઀ૢ࡞Λߦ͏ςετ w 6*5FTUͰ4IBSF&YUFOTJPOରԠͷڞ༗ը໘΋ςετՄೳ w εΫγϣΛࡱͬͯ֬ೝ͢Δ͜ͱͰ6*5FTUͰ࢖͑Δཁૉ໊͕Θ͔Δ w ڞ༗ϝχϡʔࣗମ͸ݱஈ֊ສશͰਖ਼֬ͳςετίʔυ͕ॻ͚ͳ͍ ࢀߟɿIUUQTHJUIVCDPNFMIPTIJOP2VJDLTIB3FCMPCDFGDGGEBEEDFCDFE2VJDLTIB3F6*5FTUT2VJDLTIB3F6*5FTUTTXJGU

Slide 44

Slide 44 text

ʲએ఻ʳ

Slide 45

Slide 45 text

2VJDLTIB3Fɺઈࢍ഑৴தʂ IUUQTBQQTBQQMFDPNKQBQQRVJDLTIBSFTIBSFWJBRSDPEFJE

Slide 46

Slide 46 text

גࣜձࣾΏΊΈɺΤϯδχΞઈࢍืूத IUUQSFDSVJUZVNFNJDPKQ 䱰⾂ ؽ٨ضٌ ✌؜猳