JobsUnifiedTopCard.purs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. module Test.JobsUnifiedTopCard where
  2. import Prelude
  3. import Data.Either (Either(..))
  4. import Data.Foldable (for_)
  5. import Data.List (List(..), (:))
  6. import Data.List.NonEmpty (NonEmptyList(..))
  7. import Data.Maybe (Maybe(..))
  8. import Data.NonEmpty (NonEmpty(..))
  9. import Effect.Aff (Aff)
  10. import LinkedIn.DetachedNode (DetachedNode(..))
  11. import LinkedIn.Jobs.JobOffer (JobOffer(..))
  12. import LinkedIn.Output.Types (Output(..))
  13. import LinkedIn.Page.JobOffer (JobOfferPage(..))
  14. import LinkedIn.UI.Basic.Types (JobFlexibility(..))
  15. import LinkedIn.UI.Components.JobsUnifiedTopCard (JobsUnifiedTopCardElement(..), TopCardAction(..), TopCardInsight(..), TopCardInsightContent(..), TopCardPrimaryDescription(..), TopCardSecondaryInsight(..))
  16. import Test.Spec (Spec, SpecT, describe, it)
  17. import Test.Spec.Assertions (shouldEqual)
  18. import Test.Utils (detachFromFile, getOutputFromFile)
  19. import Type.Proxy (Proxy(..))
  20. type TestCase a = {
  21. detached ∷ a DetachedNode,
  22. filePath ∷ String,
  23. id ∷ String,
  24. output ∷ Output,
  25. url ∷ String
  26. }
  27. jobsUnifiedTopCardSpec :: Spec Unit
  28. jobsUnifiedTopCardSpec = do
  29. describe "Jobs top card parsing" do
  30. for_ [jobOfferPage_3786945580, jobOfferPage_3797662873] runTest
  31. runTest ∷ ∀ m. Monad m ⇒ TestCase JobOfferPage → SpecT Aff Unit m Unit
  32. runTest {detached, filePath, id, output} = do
  33. it ("reads well as a JobOfferPage DetachedNode " <> show id) do
  34. topCard <- detachFromFile (Proxy :: Proxy JobOfferPage) filePath
  35. topCard `shouldEqual` Right(detached)
  36. it ("reads the JobOffer " <> show id) do
  37. jobOffer <- getOutputFromFile (Proxy :: Proxy JobOfferPage) filePath
  38. jobOffer `shouldEqual` Right (output)
  39. jobOfferPage_3786945580 ∷ TestCase JobOfferPage
  40. jobOfferPage_3786945580 = {
  41. id: "3786945580",
  42. filePath: "test/examples/job_offer_3786945580.html",
  43. url: "https://www.linkedin.com/jobs/view/3786945580/",
  44. detached: JobOfferPage (JobsUnifiedTopCardElement {
  45. actions: TopCardActionButton
  46. (DetachedButton {
  47. classes: ("jobs-apply-button" : "artdeco-button" : "artdeco-button--3" : "artdeco-button--primary" : "ember-view" : Nil),
  48. content: "Candidature simplifiée",
  49. role: Nothing
  50. })
  51. : TopCardActionButton (DetachedButton {
  52. classes: ("jobs-save-button" : "artdeco-button" : "artdeco-button--3" : "artdeco-button--secondary" : Nil),
  53. content: "Enregistrer Enregistrer Data Engineer H/F - Secteur Energie chez LINCOLN",
  54. role: Nothing
  55. })
  56. : Nil,
  57. header: (DetachedElement {
  58. classes: ("t-24" : "t-bold" : "job-details-jobs-unified-top-card__job-title" : Nil),
  59. content: "Data Engineer H/F - Secteur Energie",
  60. id: Nothing,
  61. tag: "H1"
  62. }),
  63. insights: (TopCardInsight {
  64. content: (TopCardInsightContentSecondary {
  65. primary: (DetachedElement {classes: Nil, content: "Sur site", id: Nothing, tag: "SPAN"}),
  66. secondary: (NonEmptyList (NonEmpty (TopCardSecondaryInsightNested
  67. (DetachedElement {classes: Nil, content: "Temps plein", id: Nothing, tag: "SPAN"}))
  68. ((TopCardSecondaryInsightPlain
  69. (DetachedElement {classes: ("job-details-jobs-unified-top-card__job-insight-view-model-secondary" : Nil), content: "Confirmé", id: Nothing,tag: "SPAN" })) : Nil))
  70. )
  71. }),
  72. icon: DetachedLiIcon "job"
  73. }) : (TopCardInsight {
  74. content: (TopCardInsightContentSingle (
  75. DetachedElement {classes: Nil, content: "201-500 employés · Technologies et services de l’information", id: Nothing, tag: "SPAN" }
  76. )),
  77. icon: DetachedLiIcon "company"
  78. }) : (TopCardInsight {
  79. content: (TopCardInsightContentSingle (
  80. DetachedElement {classes: Nil, content: "2 anciens élèves travaillent ici", id: Nothing, tag: "SPAN" }
  81. )),
  82. icon: DetachedLiIcon "people"
  83. }) : (TopCardInsight {
  84. content: (TopCardInsightContentSingle (
  85. DetachedElement {classes: Nil, content: "Découvrez comment vous vous positionnez par rapport à 87 candidats. Essai Premium pour 0 EUR", id: Nothing, tag: "SPAN" })),
  86. icon: (DetachedSvgElement { dataTestIcon: (Just "lightbulb-medium"), id: Nothing, tag: "svg" })
  87. }) : (TopCardInsight {
  88. content: (TopCardInsightContentButton (
  89. DetachedButton {classes: ("job-details-jobs-unified-top-card__job-insight-text-button" : Nil), content: "9 compétences sur 11 correspondent à votre profil, vous pourriez bien convenir pour ce poste", role: Nothing}
  90. )),
  91. icon: (DetachedSvgElement { dataTestIcon: (Just "checklist-medium"), id: Nothing, tag: "svg" })
  92. }) : Nil,
  93. primaryDescription: (TopCardPrimaryDescription {
  94. link: (DetachedA { content: "LINCOLN", href: "https://www.linkedin.com/company/lincoln-/life" }),
  95. text: (DetachedText "· Boulogne-Billancourt, Île-de-France, France"),
  96. tvmText:
  97. DetachedElement {classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "il y a 2 semaines", id: Nothing, tag: "SPAN"}
  98. : DetachedElement {classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "·", id: Nothing, tag: "SPAN"}
  99. : DetachedElement {classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "87 candidats", id: Nothing, tag: "SPAN"}
  100. : Nil
  101. })
  102. }),
  103. output: OutJobOffer (JobOffer {
  104. companyDomain: (Just "Technologies et services de l’information"),
  105. companyLink: "https://www.linkedin.com/company/lincoln-/life",
  106. companyName: "LINCOLN",
  107. companySize: (Just "201-500 employés"),
  108. hasSimplifiedApplicationProcess: true,
  109. location: (Just "Boulogne-Billancourt, Île-de-France, France"),
  110. flexibility: (Just JobFlexOnSite),
  111. title: "Data Engineer H/F - Secteur Energie"
  112. })
  113. }
  114. jobOfferPage_3797662873 ∷ TestCase JobOfferPage
  115. jobOfferPage_3797662873 = {
  116. id: "3797662873",
  117. filePath: "test/examples/job_offer_3797662873.html",
  118. url: "https://www.linkedin.com/jobs/view/3797662873/",
  119. detached: JobOfferPage (JobsUnifiedTopCardElement {
  120. actions: (TopCardActionButton
  121. (DetachedButton { classes: ("jobs-apply-button" : "artdeco-button" : "artdeco-button--3" : "artdeco-button--primary" : "ember-view" : Nil), content: "Candidature simplifiée", role: Nothing }))
  122. : ((TopCardActionButton (DetachedButton {
  123. classes: ("jobs-save-button" : "artdeco-button" : "artdeco-button--3" : "artdeco-button--secondary" : Nil),
  124. content: "Enregistrer Enregistrer Data Engineer Confirmé(e)/Senior (CDI) chez CBTW",
  125. role: Nothing
  126. })) : Nil),
  127. header: (DetachedElement {
  128. classes: ("t-24" : "t-bold" : "job-details-jobs-unified-top-card__job-title" : Nil),
  129. content: "Data Engineer Confirmé(e)/Senior (CDI)",
  130. id: Nothing,
  131. tag: "H1"
  132. }),
  133. insights: TopCardInsight {
  134. content: (TopCardInsightContentSecondary {
  135. primary: (DetachedElement { classes: Nil, content: "Hybride", id: Nothing, tag: "SPAN" }),
  136. secondary: (NonEmptyList (NonEmpty (TopCardSecondaryInsightNested
  137. (DetachedElement { classes: Nil, content: "Temps plein", id: Nothing, tag: "SPAN" })
  138. ) ((TopCardSecondaryInsightPlain (
  139. DetachedElement { classes: ("job-details-jobs-unified-top-card__job-insight-view-model-secondary" : Nil), content: "Confirmé", id: Nothing, tag: "SPAN" })) : Nil)))
  140. }),
  141. icon: (DetachedLiIcon "job")
  142. } : TopCardInsight {
  143. content: (TopCardInsightContentSingle (DetachedElement { classes: Nil, content: "1 001-5 000 employés · Développement de logiciels", id: Nothing, tag: "SPAN" })),
  144. icon: (DetachedLiIcon "company")
  145. } : TopCardInsight {
  146. content: (TopCardInsightContentSingle (DetachedElement { classes: Nil, content: "Amina Berkane recrute à ce poste", id: Nothing, tag: "SPAN" })),
  147. icon: (DetachedImg { classes: ("ivm-view-attr__img--centered" : "EntityPhoto-circle-1" : "evi-image" : "lazy-image" : "ember-view" : Nil), src: "job_offer_2_files/1706175960816.jpg" })
  148. } : TopCardInsight {
  149. content: (TopCardInsightContentButton (DetachedButton { classes: ("job-details-jobs-unified-top-card__job-insight-text-button" : Nil), content: "8 compétences sur 10 correspondent à votre profil, vous pourriez bien convenir pour ce poste", role: Nothing })),
  150. icon: (DetachedSvgElement { dataTestIcon: (Just "checklist-medium"), id: Nothing, tag: "svg" })
  151. } : TopCardInsight {
  152. content: (TopCardInsightContentSingle (DetachedElement { classes: Nil, content: "Le délai d’évaluation des candidatures est généralement de 4 jours", id: Nothing, tag: "SPAN" })),
  153. icon: (DetachedSvgElement { dataTestIcon: (Just "responsive-medium"), id: Nothing, tag: "svg" })
  154. } : TopCardInsight {
  155. content: (TopCardInsightContentSingle (DetachedElement { classes: Nil, content: "Découvrez comment vous vous positionnez par rapport à 39 candidats. Essai Premium pour 0 EUR", id: Nothing, tag: "SPAN" })),
  156. icon: (DetachedSvgElement { dataTestIcon: (Just "lightbulb-medium"), id: Nothing, tag: "svg" })
  157. } : Nil,
  158. primaryDescription: (TopCardPrimaryDescription {
  159. link: (DetachedA { content: "CBTW", href: "https://www.linkedin.com/company/collaboration-betters-the-world/life" }),
  160. text: (DetachedText "· Paris et périphérie ·"),
  161. tvmText: DetachedElement { classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "il y a 4 semaines", id: Nothing, tag: "SPAN" }
  162. : (DetachedElement { classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "·", id: Nothing, tag: "SPAN" })
  163. : (DetachedElement { classes: ("tvm__text" : "tvm__text--neutral" : Nil), content: "39 candidats", id: Nothing, tag: "SPAN" })
  164. : Nil
  165. })
  166. }),
  167. output: OutJobOffer (JobOffer {
  168. companyDomain: Just "Développement de logiciels",
  169. companyLink: "https://www.linkedin.com/company/collaboration-betters-the-world/life",
  170. companyName: "CBTW",
  171. companySize: Just "1 001-5 000 employés",
  172. flexibility: Just JobFlexHybrid,
  173. hasSimplifiedApplicationProcess: true,
  174. location: (Just "Paris et périphérie"),
  175. title: "Data Engineer Confirmé(e)/Senior (CDI)"
  176. })
  177. }